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

北京電子科技學院(BESTI)實驗報告

課程:Java2實用教程 班級:201752 姓名:姚明宇 學號:20175223
成績: 指導教師:婁嘉鵬 實驗日期:5月31日
實驗密級: 預習程度: 實驗時間:
儀器組次: 必修/選修:選修 實驗序號:

目錄java

實驗名稱:實驗五 網絡編程與安全

實驗儀器:android

名稱 型號 數量
PC端 1

實驗內容、步驟與體會:


零、"兩人一組"結對對象

20175233嚴順堯-負責客戶端
20175223姚明宇-負責服務器git


1、實驗五 網絡編程與安全-1

兩人一組結對編程:算法

  1. 參考http://www.cnblogs.com/rocedu/p/6766748.html#SECDSA
  2. 結對實現中綴表達式轉後綴表達式的功能 MyBC.java
  3. 結對實現從上面功能中獲取的表達式中實現後綴表達式求值的功能,調用MyDC.java
  4. 上傳測試代碼運行結果截圖和碼雲連接

代碼

(代碼已摺疊)
express


MyBC.java

編程


import java.util.*;
import java.util.stream.Collectors;

public class MyBC{
private static final Map<Character, Integer> basic = new HashMap<Character, Integer>();
static {
basic.put('-', 1);
basic.put('+', 1);
basic.put('*', 2);
basic.put('/', 2);
basic.put('(', 0);
}apache

//中綴表達式 轉 後綴表達式

public static String toSuffix(String infix){
    List<String> queue = new ArrayList<String>();
    List<Character> stack = new ArrayList<Character>();

    char[] charArr = infix.trim().toCharArray();
    String standard = "*/+-()";
    char ch = '&';
    int len = 0;
    for (int i = 0; i < charArr.length; i++) {

        ch = charArr[i];
        if(Character.isDigit(ch)) {
            len++;
        }else if(Character.isLetter(ch)) {
            len++;
        }else if(ch == '.'){
            len++;
        }else if(Character.isSpaceChar(ch)) {
            if(len > 0) {
                queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len, i)));
                len = 0;
            }
            continue;
        }else if(standard.indexOf(ch) != -1) {
            if(len > 0) {
                queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len, i)));
                len = 0;
            }
            if(ch == '(') {
                stack.add(ch);
                continue;
            }
            if (!stack.isEmpty()) {
                int size = stack.size() - 1;
                boolean flag = false;
                while (size >= 0 && ch == ')' && stack.get(size) != '(') {
                    queue.add(String.valueOf(stack.remove(size)));
                    size--;
                    flag = true;
                }
                while (size >= 0 && !flag && basic.get(stack.get(size)) >= basic.get(ch)) {
                    queue.add(String.valueOf(stack.remove(size)));
                    size--;
                }
            }
            if(ch != ')') {
                stack.add(ch);
            } else {
                stack.remove(stack.size() - 1);
            }
        }
        if(i == charArr.length - 1) {
            if(len > 0) {
                queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len+1, i+1)));
            }
            int size = stack.size() - 1;
            while (size >= 0) {
                queue.add(String.valueOf(stack.remove(size)));
                size--;
            }
        }
    }
    return queue.stream().collect(Collectors.joining(" "));
}
//中綴表達式 轉 後綴表達式 public static String toSuffix(String infix){ List<String> queue = new ArrayList<String>(); List<Character> stack = new ArrayList<Character>(); char[] charArr = infix.trim().toCharArray(); String standard = "*/+-()"; char ch = '&'; int len = 0; for (int i = 0; i < charArr.length; i++) { ch = charArr[i]; if(Character.isDigit(ch)) { len++; }else if(Character.isLetter(ch)) { len++; }else if(ch == '.'){ len++; }else if(Character.isSpaceChar(ch)) { if(len > 0) { queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len, i))); len = 0; } continue; }else if(standard.indexOf(ch) != -1) { if(len > 0) { queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len, i))); len = 0; } if(ch == '(') { stack.add(ch); continue; } if (!stack.isEmpty()) { int size = stack.size() - 1; boolean flag = false; while (size >= 0 && ch == ')' && stack.get(size) != '(') { queue.add(String.valueOf(stack.remove(size))); size--; flag = true; } while (size >= 0 && !flag && basic.get(stack.get(size)) >= basic.get(ch)) { queue.add(String.valueOf(stack.remove(size))); size--; } } if(ch != ')') { stack.add(ch); } else { stack.remove(stack.size() - 1); } } if(i == charArr.length - 1) { if(len > 0) { queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len+1, i+1))); } int size = stack.size() - 1; while (size >= 0) { queue.add(String.valueOf(stack.remove(size))); size--; } } } return queue.stream().collect(Collectors.joining(" ")); }}

MyDC.java
import java.util.StringTokenizer;
import java.util.Stack;

public class MyDC {
    /**
     * constant for addition symbol
     */
    private final char ADD = '+';
    /**
     * constant for subtraction symbol
     */
    private final char SUBTRACT = '-';
    /**
     * constant for multiplication symbol
     */
    private final char MULTIPLY = '*';
    /**
     * constant for division symbol
     */
    private final char DIVIDE = '/';
    /**
     * the stack
     */
    private Stack 
   
   
   

  
   
  stack; public MyDC() { stack = new Stack 
 
   
     ( ); } public int evaluate(String expr) { int op1, op2, result = 0; String token; StringTokenizer tokenizer = new StringTokenizer (expr); while (tokenizer.hasMoreTokens ( )) { token = tokenizer.nextToken ( ); //若是是運算符,調用isOperator if (isOperator(token)==true) { op2=stack.pop(); op1=stack.pop(); //從棧中彈出操做數2 //從棧中彈出操做數1 result=evalSingleOp(token.charAt(0),op1,op2); //根據運算符和兩個操做數調用evalSingleOp計算result; stack.push(result); //計算result入棧; } else//若是是操做數 { stack.push(Integer.parseInt(token)); } //操做數入棧; } return result; } private boolean isOperator(String token) { return (token.equals ("+") || token.equals ("-") || token.equals ("*") || token.equals ("/")); } private int evalSingleOp(char operation, int op1, int op2) { int result = 0; switch (operation) { case ADD: result = op1 + op2; break; case SUBTRACT: result = op1 - op2; break; case MULTIPLY: result = op1 * op2; break; case DIVIDE: result = op1 / op2; break; default:return 0; } return result; } } 
    

  
Client.java
import java.util.Scanner;

public class MyBCTest {
    public static void main(String[] args) {
        MyBC mybc = new MyBC ();
        MyDC mydc = new MyDC ();
        String inExpression;
        String str;
        Scanner reader = new Scanner (System.in);
        System.out.println ("Enter a expression: ");
        inExpression = reader.nextLine ();
        str = mybc.toSuffix (inExpression);
        System.out.println ("Exchange the expression by MyBC: " +str);
        System.out.println ("The calculation result of MyDC: " +mydc.evaluate(str));
    }
}

過程

實現後綴表達式求值的功能:數組

MyDC evaluator = new MyDC ( );
//用 Scanner 輸入 evaluator 的內容
String result = evaluator.evaluate (expression);
//輸出 result

截圖

image.png


2、實驗五 網絡編程與安全-2

結對編程:1人負責客戶端,一人負責服務器安全

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

代碼

(代碼已摺疊)


Client.java


import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import java.util.Scanner;

public class Client {
public static void main(String args[]) {
Scanner reader = new Scanner (System.in);
System.out.println ("客戶輸入一箇中綴表達式: ");
String str = reader.nextLine ();
Socket mysocket;
DataInputStream in = null;
DataOutputStream out = null;
try {
mysocket = new Socket ("127.0.0.1", 2010);
in = new DataInputStream (mysocket.getInputStream ( ));
out = new DataOutputStream (mysocket.getOutputStream ( ));
out.writeUTF (str);
//in讀取信息,堵塞狀態
String temp = in.readUTF ( );
System.out.println ("客戶收到服務器的後綴表達式:\n" + temp);
String answer = in.readUTF ( );
System.out.println ("客戶收到服務器的計算結果:\n" + answer);
Thread.sleep (500);
} catch (Exception e) {
System.out.println ("服務器已斷開" + e);
}
}
}

Server.java
import java.io.*;
import java.net.*;

public class Server {
    public static void main(String args[]) {
        String question, temp, answer;
        MyDC mydc = new MyDC ();
        ServerSocket serverForClient = null;
        Socket socketOnServer = null;
        DataOutputStream out = null;
        DataInputStream in = null;
        try {
            serverForClient = new ServerSocket (2010);
        } catch (IOException e1) {
            System.out.println (e1);
        }
        try {
            System.out.println ("等待客戶呼叫");
            //堵塞狀態,除非有客戶呼叫
            socketOnServer = serverForClient.accept ( );
            out = new DataOutputStream (socketOnServer.getOutputStream ( ));
            in = new DataInputStream (socketOnServer.getInputStream ( ));
            // in讀取信息,堵塞狀態
            question = in.readUTF ( );
            System.out.println ("服務器收到客戶的中綴表達式:\n" + question);
            temp = MyBC.toSuffix (question);
            System.out.println ("服務器將中綴表達式變形爲後綴表達式:\n" +temp);
            out.writeUTF (temp);
            answer = String.valueOf(mydc.evaluate(temp));
            out.writeUTF (answer);
            Thread.sleep (500);
        } catch (Exception e) {
            System.out.println ("客戶已斷開" + e);
        }
    }
}

過程

1.服務器創建連接。

ServerSocket serverForClient = new ServerSocket (2010);;
Socket socketOnServer = null;
socketOnServer = serverForClient.accept ( );

客戶端創建對應連接相連。
Socket mysocket = new Socket ("127.0.0.1", 2010);
再建立 in , out 對象,使用 in.readUTF(); out.writeUTF(); 進行數據交換。
2.服務器實現把中綴表達式轉化爲後綴表達式的功能:
String temp = MyBC.toSuffix (question);
注:因爲 MyBC 類中的 toSuffix() 方法爲 public static 靜態方法,能夠直接經過類名調用。
3.服務器實現後綴表達式求值的功能:

MyDC str = new MyDC ( );
String result = str.evaluate (expression);

4.服務器經過 out.writeUTF(result); 輸出 result;客戶端經過 in.readUTF(); 接受後,打印輸出。

截圖

image.png
image.png


3、實驗五 網絡編程與安全-3

加密結對編程:1人負責客戶端,一人負責服務器

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

代碼

(代碼已摺疊)


AES.java


import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

public class AES {
public static String ecodes(String content, String key) {
if (content == null || content.length ( ) < 1) {
return null;
}
try {
KeyGenerator kgen = KeyGenerator.getInstance ("AES");
SecureRandom random = SecureRandom.getInstance ("SHA1PRNG");
random.setSeed (key.getBytes ( ));
kgen.init (128, random);
SecretKey secretKey = kgen.generateKey ( );
byte[] enCodeFormat = secretKey.getEncoded ( );
SecretKeySpec secretKeySpec = new SecretKeySpec (enCodeFormat, "AES");
Cipher cipher = Cipher.getInstance ("AES");
byte[] byteContent = content.getBytes ("utf-8");
cipher.init (Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] byteRresult = cipher.doFinal (byteContent);
StringBuffer sb = new StringBuffer ( );
for (int i = 0; i < byteRresult.length; i++) {
String hex = Integer.toHexString (byteRresult[i] & 0xFF);
if (hex.length ( ) == 1) {
hex = '0' + hex;
}
sb.append (hex.toUpperCase ( ));
}
return sb.toString ( );
} catch (NoSuchAlgorithmException e) {
e.printStackTrace ( );
} catch (NoSuchPaddingException e) {
e.printStackTrace ( );
} catch (InvalidKeyException e) {
e.printStackTrace ( );
} catch (UnsupportedEncodingException e) {
e.printStackTrace ( );
} catch (IllegalBlockSizeException e) {
e.printStackTrace ( );
} catch (BadPaddingException e) {
e.printStackTrace ( );
}
return null;
}

public static String dcodes(String content, String key) {
    if (content == null || content.length ( ) < 1) {
        return null;
    }
    if (content.trim ( ).length ( ) < 19) {
        return content;
    }
    byte[] byteRresult = new byte[content.length ( ) / 2];
    for (int i = 0; i < content.length ( ) / 2; i++) {
        int high = Integer.parseInt (content.substring (i * 2, i * 2 + 1), 16);
        int low = Integer.parseInt (content.substring (i * 2 + 1, i * 2 + 2), 16);
        byteRresult[i] = (byte) (high * 16 + low);
    }
    try {
        KeyGenerator kgen = KeyGenerator.getInstance ("AES");
        SecureRandom random = SecureRandom.getInstance ("SHA1PRNG");
        random.setSeed (key.getBytes ( ));
        kgen.init (128, random);
        SecretKey secretKey = kgen.generateKey ( );
        byte[] enCodeFormat = secretKey.getEncoded ( );
        SecretKeySpec secretKeySpec = new SecretKeySpec (enCodeFormat, "AES");
        Cipher cipher = Cipher.getInstance ("AES");
        cipher.init (Cipher.DECRYPT_MODE, secretKeySpec);
        byte[] result = cipher.doFinal (byteRresult);
        return new String (result);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace ( );
    } catch (NoSuchPaddingException e) {
        e.printStackTrace ( );
    } catch (InvalidKeyException e) {
        e.printStackTrace ( );
    } catch (IllegalBlockSizeException e) {
        e.printStackTrace ( );
    } catch (BadPaddingException e) {
        e.printStackTrace ( );
    }
    return null;
}

}

public static String dcodes(String content, String key) { if (content == null || content.length ( ) < 1) { return null; } if (content.trim ( ).length ( ) < 19) { return content; } byte[] byteRresult = new byte[content.length ( ) / 2]; for (int i = 0; i < content.length ( ) / 2; i++) { int high = Integer.parseInt (content.substring (i * 2, i * 2 + 1), 16); int low = Integer.parseInt (content.substring (i * 2 + 1, i * 2 + 2), 16); byteRresult[i] = (byte) (high * 16 + low); } try { KeyGenerator kgen = KeyGenerator.getInstance ("AES"); SecureRandom random = SecureRandom.getInstance ("SHA1PRNG"); random.setSeed (key.getBytes ( )); kgen.init (128, random); SecretKey secretKey = kgen.generateKey ( ); byte[] enCodeFormat = secretKey.getEncoded ( ); SecretKeySpec secretKeySpec = new SecretKeySpec (enCodeFormat, "AES"); Cipher cipher = Cipher.getInstance ("AES"); cipher.init (Cipher.DECRYPT_MODE, secretKeySpec); byte[] result = cipher.doFinal (byteRresult); return new String (result); } catch (NoSuchAlgorithmException e) { e.printStackTrace ( ); } catch (NoSuchPaddingException e) { e.printStackTrace ( ); } catch (InvalidKeyException e) { e.printStackTrace ( ); } catch (IllegalBlockSizeException e) { e.printStackTrace ( ); } catch (BadPaddingException e) { e.printStackTrace ( ); } return null; }

ServerAES.java
import java.io.*;
import java.net.*;

public class ServerAES {
    public static void main(String args[]) {
        String miwen, temp, answer;
        MyDC mydc = new MyDC ( );
        ServerSocket serverForClient = null;
        Socket socketOnServer = null;
        DataOutputStream out = null;
        DataInputStream in = null;
        try {
            serverForClient = new ServerSocket (2010);
        } catch (IOException e1) {
            System.out.println (e1);
        }
        try {
            System.out.println ("等待客戶呼叫");
            //堵塞狀態,除非有客戶呼叫
            socketOnServer = serverForClient.accept ( );
            out = new DataOutputStream (socketOnServer.getOutputStream ( ));
            in = new DataInputStream (socketOnServer.getInputStream ( ));
            // in讀取信息,堵塞狀態
            miwen = in.readUTF ( );
            System.out.println ("服務器收到客戶的密文:\n" + miwen);
            String key = "20175223yaomingyushidashuaibi111";
            String mingwen = AES.dcodes (miwen, key);
            answer = String.valueOf (mydc.evaluate (mingwen));
            out.writeUTF (answer);
            System.out.println ("\n**計算結果由客戶端打印輸出**");
            Thread.sleep (500);
        } catch (Exception e) {
            System.out.println ("客戶已斷開" + e);
        }
    }
}
ClientAES.java
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import java.util.Scanner;

public class ClientAES {
    public static void main(String args[]) {
        Scanner reader = new Scanner (System.in);
        System.out.println ("客戶輸入一箇中綴表達式: ");
        String str = reader.nextLine ( );
        Socket mysocket;
        DataInputStream in = null;
        DataOutputStream out = null;
        try {
            mysocket = new Socket ("127.0.0.1", 2010);
            in = new DataInputStream (mysocket.getInputStream ( ));
            out = new DataOutputStream (mysocket.getOutputStream ( ));
            String key = "20175223yaomingyushidashuaibi111";
            //將中綴表達式變形爲後綴表達式
            String temp = MyBC.toSuffix (str);
            System.out.println ("服務器將中綴表達式變形爲後綴表達式:\n" + temp);
            //輸入密文,32字符密鑰
            String miwen = AES.ecodes (temp, key);
            System.out.println ("客戶發往服務器的密文:\n" + miwen + "\n");
            out.writeUTF (miwen);
            //in讀取信息,堵塞狀態
            String answer = in.readUTF ( );
            System.out.println ("客戶收到服務器的計算結果:\n" + answer);
            Thread.sleep (500);
        } catch (Exception e) {
            System.out.println ("服務器已斷開" + e);
        }
    }
}

過程

1.首先,服務器和客戶端協商密鑰爲:String key = "20175223yaomingyushidashuaibi111"; ,各自存在本地;
AES算法及其相關方法經過 AES.java 實現。
2.客戶端實現把中綴表達式轉化爲後綴表達式的功能(同 網絡編程與安全-2),將後綴表達式明文加密:

String  = MyBC.toSuffix (str);
String miwen = AES.ecodes(mingwen,key);

再發往服務器。
3.服務器將接收到的密文用密鑰解密,調用方法 mydc.evaluate() 計算後綴表達式:

String mingwen = AES.dcodes(miwen, key);
String answer = String.valueOf(mydc.evaluate(mingwen));

4.服務器將答案發往客戶端,由客戶端打印輸出。

截圖

image.png
image.png
image.png


4、實驗五 網絡編程與安全-4

密鑰分發結對編程:1人負責客戶端,一人負責服務器

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

代碼

(代碼已摺疊)


DH.java
  
  
  
  

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
import javax.crypto.interfaces.DHPrivateKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**

  • 非對稱加密算法DH算法組件
  • 非對稱算法通常是用來傳送對稱加密算法的密鑰來使用的,因此這裏咱們用DH算法模擬密鑰傳送
  • 對稱加密AES算法繼續作咱們的數據加解密
  • @author kongqz
  • */
    public class DH {
    //非對稱密鑰算法
    public static final String KEY_ALGORITHM="DH";

    //本地密鑰算法,即對稱加密算法。可選des,aes,desede
    public static final String SECRET_ALGORITHM="AES";

    /**
    • 密鑰長度,DH算法的默認密鑰長度是1024
    • 密鑰長度必須是64的倍數,在512到1024位之間
    • */
      private static final int KEY_SIZE=512;
      //公鑰
      private static final String PUBLIC_KEY="DHPublicKey";

    //私鑰
    private static final String PRIVATE_KEY="DHPrivateKey";

    /**
    • 初始化甲方密鑰
    • @return Map 甲方密鑰的Map
    • */
      public static Map<String,Object> initKey() throws Exception{
      //實例化密鑰生成器
      KeyPairGenerator keyPairGenerator=KeyPairGenerator.getInstance(KEY_ALGORITHM);
      //初始化密鑰生成器
      keyPairGenerator.initialize(KEY_SIZE);
      //生成密鑰對
      KeyPair keyPair=keyPairGenerator.generateKeyPair();
      //甲方公鑰
      DHPublicKey publicKey=(DHPublicKey) keyPair.getPublic();
      //甲方私鑰
      DHPrivateKey privateKey=(DHPrivateKey) keyPair.getPrivate();
      //將密鑰存儲在map中
      Map<String,Object> keyMap=new HashMap<String,Object>();
      keyMap.put(PUBLIC_KEY, publicKey);
      keyMap.put(PRIVATE_KEY, privateKey);
      return keyMap;

    }

    /**
    • 初始化乙方密鑰
    • @param key 甲方密鑰(這個密鑰是經過第三方途徑傳遞的)
    • @return Map 乙方密鑰的Map
    • */
      public static Map<String,Object> initKey(byte[] key) throws Exception{
      //解析甲方的公鑰
      //轉換公鑰的材料
      X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(key);
      //實例化密鑰工廠
      KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
      //產生公鑰
      PublicKey pubKey=keyFactory.generatePublic(x509KeySpec);
      //由甲方的公鑰構造乙方密鑰
      DHParameterSpec dhParamSpec=((DHPublicKey)pubKey).getParams();
      //實例化密鑰生成器
      KeyPairGenerator keyPairGenerator=KeyPairGenerator.getInstance(keyFactory.getAlgorithm());
      //初始化密鑰生成器
      keyPairGenerator.initialize(dhParamSpec);
      //產生密鑰對
      KeyPair keyPair=keyPairGenerator.genKeyPair();
      //乙方公鑰
      DHPublicKey publicKey=(DHPublicKey)keyPair.getPublic();
      //乙方私鑰
      DHPrivateKey privateKey=(DHPrivateKey)keyPair.getPrivate();
      //將密鑰存儲在Map中
      Map<String,Object> keyMap=new HashMap<String,Object>();
      keyMap.put(PUBLIC_KEY, publicKey);
      keyMap.put(PRIVATE_KEY, privateKey);
      return keyMap;
      }
      /**
    • 加密
    • @param data 待加密數據
    • @param key 密鑰
    • @return byte[] 加密數據
    • */
      public static byte[] encrypt(byte[] data,byte[] key) throws Exception{
      //生成本地密鑰
      SecretKey secretKey=new SecretKeySpec(key,SECRET_ALGORITHM);
      //數據加密
      Cipher cipher=Cipher.getInstance(secretKey.getAlgorithm());
      cipher.init(Cipher.ENCRYPT_MODE, secretKey);
      return cipher.doFinal(data);
      }
      /**
    • 解密
    • @param data 待解密數據
    • @param key 密鑰
    • @return byte[] 解密數據
    • */
      public static byte[] decrypt(byte[] data,byte[] key) throws Exception{
      //生成本地密鑰
      SecretKey secretKey=new SecretKeySpec(key,SECRET_ALGORITHM);
      //數據解密
      Cipher cipher=Cipher.getInstance(secretKey.getAlgorithm());
      cipher.init(Cipher.DECRYPT_MODE, secretKey);
      return cipher.doFinal(data);
      }
      /**
    • 構建密鑰
    • @param publicKey 公鑰
    • @param privateKey 私鑰
    • @return byte[] 本地密鑰
    • */
      public static byte[] getSecretKey(byte[] publicKey,byte[] privateKey) throws Exception{
      //實例化密鑰工廠
      KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
      //初始化公鑰
      //密鑰材料轉換
      X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(publicKey);
      //產生公鑰
      PublicKey pubKey=keyFactory.generatePublic(x509KeySpec);
      //初始化私鑰
      //密鑰材料轉換
      PKCS8EncodedKeySpec pkcs8KeySpec=new PKCS8EncodedKeySpec(privateKey);
      //產生私鑰
      PrivateKey priKey=keyFactory.generatePrivate(pkcs8KeySpec);
      //實例化
      KeyAgreement keyAgree=KeyAgreement.getInstance(keyFactory.getAlgorithm());
      //初始化
      keyAgree.init(priKey);
      keyAgree.doPhase(pubKey, true);
      //生成本地密鑰
      SecretKey secretKey=keyAgree.generateSecret(SECRET_ALGORITHM);
      return secretKey.getEncoded();
      }
      /**
    • 取得私鑰
    • @param keyMap 密鑰map
    • @return byte[] 私鑰
    • */
      public static byte[] getPrivateKey(Map<String,Object> keyMap){
      Key key=(Key)keyMap.get(PRIVATE_KEY);
      return key.getEncoded();
      }
      /**
    • 取得公鑰
    • @param keyMap 密鑰map
    • @return byte[] 公鑰
    • */
      public static byte[] getPublicKey(Map<String,Object> keyMap) throws Exception{
      Key key=(Key) keyMap.get(PUBLIC_KEY);
      return key.getEncoded();
      }
      /**
    • @param args
    • @throws Exception
      */
      public static void main(String[] args) throws Exception {
      //生成甲方的密鑰對
      Map<String,Object> keyMap1=DH.initKey();
      //甲方的公鑰
      byte[] publicKey1=DH.getPublicKey(keyMap1);

      //甲方的私鑰
      byte[] privateKey1=DH.getPrivateKey(keyMap1);
      System.out.println("甲方公鑰:/n"+Base64.encodeBase64String(publicKey1));
      System.out.println("甲方私鑰:/n"+Base64.encodeBase64String(privateKey1));

      //由甲方的公鑰產生的密鑰對
      Map<String,Object> keyMap2=DH.initKey(publicKey1);
      byte[] publicKey2=DH.getPublicKey(keyMap2);
      byte[] privateKey2=DH.getPrivateKey(keyMap2);
      System.out.println("乙方公鑰:/n"+Base64.encodeBase64String(publicKey2));
      System.out.println("乙方私鑰:/n"+Base64.encodeBase64String(privateKey2));

      //組裝甲方的本地加密密鑰,由乙方的公鑰和甲方的私鑰組合而成
      byte[] key1=DH.getSecretKey(publicKey2, privateKey1);
      System.out.println("甲方的本地密鑰:/n"+Base64.encodeBase64String(key1));

      //組裝乙方的本地加密密鑰,由甲方的公鑰和乙方的私鑰組合而成
      byte[] key2=DH.getSecretKey(publicKey1, privateKey2);
      System.out.println("乙方的本地密鑰:/n"+Base64.encodeBase64String(key2));

      System.out.println("================密鑰對構造完畢,開始進行加密數據的傳輸=============");
      String str="密碼交換算法";
      System.out.println("/n===========甲方向乙方發送加密數據==============");
      System.out.println("原文:"+str);
      System.out.println("===========使用甲方本地密鑰對進行數據加密==============");
      //甲方進行數據的加密
      byte[] code1=DH.encrypt(str.getBytes(), key1);
      System.out.println("加密後的數據:"+Base64.encodeBase64String(code1));

      System.out.println("===========使用乙方本地密鑰對數據進行解密==============");
      //乙方進行數據的解密
      byte[] decode1=DH.decrypt(code1, key2);
      System.out.println("乙方解密後的數據:"+new String(decode1)+"/n/n");

      System.out.println("===========反向進行操做,乙方向甲方發送數據==============/n/n");

      str="乙方向甲方發送數據DH";

      System.out.println("原文:"+str);

      //使用乙方本地密鑰對數據進行加密
      byte[] code2=DH.encrypt(str.getBytes(), key2);
      System.out.println("===========使用乙方本地密鑰對進行數據加密==============");
      System.out.println("加密後的數據:"+Base64.encodeBase64String(code2));

      System.out.println("=============乙方將數據傳送給甲方======================");
      System.out.println("===========使用甲方本地密鑰對數據進行解密==============");

      //甲方使用本地密鑰對數據進行解密
      byte[] decode2=DH.decrypt(code2, key1);

      System.out.println("甲方解密後的數據:"+new String(decode2));
      }
      }


  • ClientDH.java
    import org.apache.commons.codec.binary.Base64;
    
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.net.Socket;
    import java.util.Map;
    import java.util.Scanner;
    
    public class ClientDH {
        public static void main(String args[]) {
            String cipherText, plainText, answer;
            Scanner reader = new Scanner (System.in);
            System.out.println ("客戶輸入一箇中綴表達式: ");
            String str = reader.nextLine ();
            Socket mysocket;
            DataInputStream in = null;
            DataOutputStream out = null;
            try {
                mysocket = new Socket ("127.0.0.1", 2010);
                in = new DataInputStream (mysocket.getInputStream ( ));
                out = new DataOutputStream (mysocket.getOutputStream ( ));
    
                //設立AES算法的32字符密鑰,輸入密文與密鑰
                String AES_Key = "20175223yaomingyushidashuaibi111";
                //將中綴表達式變形爲後綴表達式
                plainText = MyBC.toSuffix (str);
                System.out.println ("後綴表達式明文:\n" + plainText);
    
                //將後綴表達式明文經過AES加密,並將後綴表達式密文發往客戶端
                cipherText = AES.ecodes (plainText, AES_Key);
                System.out.println ("後綴表達式密文:\n" + cipherText + "\n");
                //out發送信息
                out.writeUTF (cipherText);
    
                //對AES算法的32字符密鑰進行DH算法加密
                //生成客戶端的密鑰對
                Map 
       
       
       
    
      
       
      keyMap1 = DH.initKey ( ); //客戶端的公鑰 byte[] publicKey1 = DH.getPublicKey (keyMap1); //客戶端的私鑰 byte[] privateKey1 = DH.getPrivateKey (keyMap1); System.out.println ("客戶端公鑰:/n" + Base64.encodeBase64String (publicKey1)); System.out.println ("客戶端私鑰:/n" + Base64.encodeBase64String (privateKey1)); String tempKey1 = Base64.encodeBase64String (publicKey1); //out發送信息 out.writeUTF (tempKey1); //組裝客戶端的本地加密密鑰,由服務器的公鑰和客戶端的私鑰組合而成 //in讀取信息,堵塞狀態 String tempKey2 = in.readUTF ( ); byte[] publicKey2 = Base64.decodeBase64 (tempKey2); System.out.println ("服務器公鑰:/n" + Base64.encodeBase64String (publicKey1)); byte[] key1 = DH.getSecretKey (publicKey2, privateKey1); System.out.println ("客戶端的本地密鑰:/n" + Base64.encodeBase64String (key1)); //客戶端使用本地密鑰對AES_Key進行消息加密,併發給服務器 byte[] code1 = DH.encrypt (AES_Key.getBytes ( ), key1); System.out.println ("客戶端使用本地密鑰對AES_Key進行加密後的數據:" + Base64.encodeBase64String (code1)); //out發送信息,333333 out.writeUTF (Base64.encodeBase64String (code1)); //接受服務器的計算結果 answer = in.readUTF ( ); System.out.println ("\n**計算由服務器進行**\n\n客戶收到服務器的計算結果:\n" + answer); Thread.sleep (500); } catch (Exception e) { System.out.println ("服務器已斷開" + e); } } } 
    
      
    ServerDH.java
    import org.apache.commons.codec.binary.Base64;
    
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.IOException;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.Map;
    
    public class ServerDH {
        public static void main(String args[]) {
            String cipherText, plainText, answer;
            MyDC mydc = new MyDC ( );
            ServerSocket serverForClient = null;
            Socket socketOnServer = null;
            DataOutputStream out = null;
            DataInputStream in = null;
            try {
                serverForClient = new ServerSocket (2010);
            } catch (IOException e1) {
                System.out.println (e1);
            }
            try {
                System.out.println ("等待客戶呼叫");
                //堵塞狀態,除非有客戶呼叫
                socketOnServer = serverForClient.accept ( );
                out = new DataOutputStream (socketOnServer.getOutputStream ( ));
                in = new DataInputStream (socketOnServer.getInputStream ( ));
                // in讀取信息,堵塞狀態
                cipherText = in.readUTF ( );
                System.out.println ("服務器收到客戶的後綴表達式密文:\n" + cipherText + "\n");
    
    
                //由客戶端的公鑰產生的密鑰對
                // in讀取信息,堵塞狀態
                String tempKey1 = in.readUTF ( );
                byte[] publicKey1 = Base64.decodeBase64 (tempKey1);
                System.out.println ("客戶端公鑰:/n" + Base64.encodeBase64String (publicKey1));
                Map 
       
       
       
    
      
       
      keyMap2 = DH.initKey (publicKey1); byte[] publicKey2 = DH.getPublicKey (keyMap2); byte[] privateKey2 = DH.getPrivateKey (keyMap2); System.out.println ("服務器公鑰:/n" + Base64.encodeBase64String (publicKey2)); System.out.println ("服務器私鑰:/n" + Base64.encodeBase64String (privateKey2)); //爲組裝客戶端的本地加密密鑰,將服務器的公鑰發給客戶端 String tempKey2 = Base64.encodeBase64String (publicKey2); //out發送信息 out.writeUTF (tempKey2); //組裝服務器的本地加密密鑰,由客戶端的公鑰和服務器的私鑰組合而成 byte[] key2 = DH.getSecretKey (publicKey1, privateKey2); System.out.println ("服務器的本地密鑰:/n" + Base64.encodeBase64String (key2)); //接受客戶端的AES_Key的加密信息,對其解密 byte[] code1 = Base64.decodeBase64 (in.readUTF ( )); byte[] decode1 = DH.decrypt (code1, key2); String AES_Key = new String (decode1); System.out.println ("\n服務器解密後的AES_Key數據:" + AES_Key); //使用解密後的AES_Key對後綴表達式密文解密,並算出結果 plainText = AES.dcodes (cipherText, AES_Key); System.out.println ("\nAES_Key對後綴表達式密文解密:\n" + plainText); answer = String.valueOf (mydc.evaluate (plainText)); //將計算結果發給客戶端 out.writeUTF (answer); System.out.println ("\n**結果由客戶端進行輸出**" ); Thread.sleep (500); } catch (Exception e) { System.out.println ("客戶已斷開" + e); } } } 
    
      

    過程

    網絡編程與安全-3 基礎上,利用成熟的 DH 算法(實現於 DH.java)實現 AES 密鑰客戶端和服務器加解密,具體步驟以下:

    //生成客戶端的密鑰對
    Map<String,Object> keyMap1=DH.initKey();
    //客戶端的公鑰
    byte[] publicKey1=DH.getPublicKey(keyMap1);
    
    //客戶端的私鑰
    byte[] privateKey1=DH.getPrivateKey(keyMap1);
    
    //由客戶端的公鑰產生的密鑰對
    Map<String,Object> keyMap2=DH.initKey(publicKey1);
    byte[] publicKey2=DH.getPublicKey(keyMap2);
    byte[] privateKey2=DH.getPrivateKey(keyMap2);
    
    //組裝客戶端的本地加密密鑰,由服務器的公鑰和客戶端的私鑰組合而成
    byte[] key1=DH.getSecretKey(publicKey2, privateKey1);
    
    //組裝服務器的本地加密密鑰,由客戶端的公鑰和服務器的私鑰組合而成
    byte[] key2=DH.getSecretKey(publicKey1, privateKey2);
    
    //客戶端進行數據的加密
    byte[] code1=DH.encrypt(str.getBytes(), key1);
    
    //服務器進行數據的解密
    byte[] decode1=DH.decrypt(code1, key2);
    
    //使用服務器本地密鑰對數據進行加密
    byte[] code2=DH.encrypt(str.getBytes(), key2);
    
    //客戶端使用本地密鑰對數據進行解密
    byte[] decode2=DH.decrypt(code2, key1);

    截圖

    image.png
    image.png
    image.png


    5、實驗四 Android程序設計-5

    完整性校驗結對編程:1人負責客戶端,一人負責服務器

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

    代碼

    (代碼已摺疊)


    MD5.java


    import java.security.MessageDigest;

    public class MD5 {
    public static String numberMD5(String plainText) throws Exception {
    String x = plainText;
    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);
    }

        return result;
    }
    return result; }}

    ClientMD5.java
    import org.apache.commons.codec.binary.Base64;
    
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.net.Socket;
    import java.util.Map;
    import java.util.Scanner;
    
    public class ClientMD5 {
        public static void main(String args[]) {
            String cipherText, plainText, answer;
            Scanner reader = new Scanner (System.in);
            System.out.println ("客戶輸入一箇中綴表達式: ");
            String str = reader.nextLine ();
            Socket mysocket;
            DataInputStream in = null;
            DataOutputStream out = null;
            try {
                mysocket = new Socket ("127.0.0.1", 2010);
                in = new DataInputStream (mysocket.getInputStream ( ));
                out = new DataOutputStream (mysocket.getOutputStream ( ));
    
                //設立AES算法的32字符密鑰,輸入密文與密鑰
                String AES_Key = "20175223yaomingyushidashuaibi111";
                //將中綴表達式變形爲後綴表達式
                plainText = MyBC.toSuffix (str);
                System.out.println ("後綴表達式明文:\n" + plainText);
    
                //將後綴表達式明文經過AES加密,並將後綴表達式密文發往服務器
                cipherText = AES.ecodes (plainText, AES_Key);
                System.out.println ("後綴表達式密文:\n" + cipherText + "\n");
                //out發送信息
                out.writeUTF (cipherText);
    
    
                //對AES算法的32字符密鑰進行DH算法加密
                //生成客戶端的密鑰對
                Map 
       
       
       
    
      
       
      keyMap1 = DH.initKey ( ); //客戶端的公鑰 byte[] publicKey1 = DH.getPublicKey (keyMap1); //客戶端的私鑰 byte[] privateKey1 = DH.getPrivateKey (keyMap1); System.out.println ("客戶端公鑰:/n" + Base64.encodeBase64String (publicKey1)); System.out.println ("客戶端私鑰:/n" + Base64.encodeBase64String (privateKey1)); String tempKey1 = Base64.encodeBase64String (publicKey1); //out發送信息 out.writeUTF (tempKey1); //組裝客戶端的本地加密密鑰,由服務器的公鑰和客戶端的私鑰組合而成 //in讀取信息,堵塞狀態 String tempKey2 = in.readUTF ( ); byte[] publicKey2 = Base64.decodeBase64 (tempKey2); System.out.println ("服務器公鑰:/n" + Base64.encodeBase64String (publicKey1)); byte[] key1 = DH.getSecretKey (publicKey2, privateKey1); System.out.println ("客戶端的本地密鑰:/n" + Base64.encodeBase64String (key1)); //客戶端使用本地密鑰對AES_Key進行消息加密,併發給服務器 byte[] code1 = DH.encrypt (AES_Key.getBytes ( ), key1); System.out.println ("客戶端使用本地密鑰對AES_Key進行加密後的數據:" + Base64.encodeBase64String (code1)); //out發送信息 out.writeUTF (Base64.encodeBase64String (code1)); //計算後綴表達式明文的MD5值,併發往服務器 String valueMD5 = MD5.numberMD5 (plainText); System.out.println ("\n客戶端計算的MD5值:" + valueMD5); //out發送信息 out.writeUTF (valueMD5); //接受服務器的計算結果 answer = in.readUTF ( ); System.out.println ("\n**計算由服務器進行**\n\n客戶收到服務器的計算結果:\n" + answer); Thread.sleep (500); } catch (Exception e) { System.out.println ("服務器已斷開" + e); } } } 
    
      
    ServerMD5.java
    import org.apache.commons.codec.binary.Base64;
    
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.IOException;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.Map;
    public class ServerMD5 {
        public static void main(String args[]) {
            String cipherText, plainText, answer;
            MyDC mydc = new MyDC ( );
            ServerSocket serverForClient = null;
            Socket socketOnServer = null;
            DataOutputStream out = null;
            DataInputStream in = null;
            try {
                serverForClient = new ServerSocket (2010);
            } catch (IOException e1) {
                System.out.println (e1);
            }
            try {
                System.out.println ("等待客戶呼叫");
                //堵塞狀態,除非有客戶呼叫
                socketOnServer = serverForClient.accept ( );
                out = new DataOutputStream (socketOnServer.getOutputStream ( ));
                in = new DataInputStream (socketOnServer.getInputStream ( ));
                // in讀取信息,堵塞狀態
                cipherText = in.readUTF ( );
                System.out.println ("服務器收到客戶的後綴表達式密文:\n" + cipherText + "\n");
    
    
                //由客戶端的公鑰產生的密鑰對
                // in讀取信息,堵塞狀態
                String tempKey1 = in.readUTF ( );
                byte[] publicKey1 = Base64.decodeBase64 (tempKey1);
                System.out.println ("客戶端公鑰:/n" + Base64.encodeBase64String (publicKey1));
                Map 
       
       
       
    
      
       
      keyMap2 = DH.initKey (publicKey1); byte[] publicKey2 = DH.getPublicKey (keyMap2); byte[] privateKey2 = DH.getPrivateKey (keyMap2); System.out.println ("服務器公鑰:/n" + Base64.encodeBase64String (publicKey2)); System.out.println ("服務器私鑰:/n" + Base64.encodeBase64String (privateKey2)); //爲組裝客戶端的本地加密密鑰,將服務器的公鑰發給客戶端 String tempKey2 = Base64.encodeBase64String (publicKey2); //out發送信息 out.writeUTF (tempKey2); //組裝服務器的本地加密密鑰,由客戶端的公鑰和服務器的私鑰組合而成 byte[] key2 = DH.getSecretKey (publicKey1, privateKey2); System.out.println ("服務器的本地密鑰:/n" + Base64.encodeBase64String (key2)); //接受客戶端的AES_Key的加密信息,對其解密 byte[] code1 = Base64.decodeBase64 (in.readUTF ( )); byte[] decode1 = DH.decrypt (code1, key2); String AES_Key = new String (decode1); System.out.println ("\n服務器解密後的AES_Key數據:" + AES_Key); //使用解密後的AES_Key對後綴表達式密文解密,並算出結果 plainText = AES.dcodes (cipherText, AES_Key); System.out.println ("\nAES_Key對後綴表達式密文解密:" + plainText); answer = String.valueOf (mydc.evaluate (plainText)); //接受客戶端的MD5值,計算解密後後綴表達式的MD5值,並判斷是否相同,不一樣則中止 String clicetValueMD5 = in.readUTF (); String valueMD5 = MD5.numberMD5 (plainText); if (!clicetValueMD5.equals (valueMD5)) { return; } System.out.println ("\n服務器MD5值:"+valueMD5 +"\n**與客戶端相同**"); //將計算結果發給客戶端 out.writeUTF (answer); System.out.println ("\n**結果由客戶端進行輸出**" ); Thread.sleep (500); } catch (Exception e) { System.out.println ("客戶已斷開" + e); } } } 
    
      

    過程

    1.實現 MD5 算法:
    將參考代碼 public static void main 改成可調用的靜態方法(於上 MD5.java):
    public static String numberMD5(String plainText)

    參考代碼:DigestPass.java
    import java.security.*;
    
    public class DigestPass{
         public static void main(String args[ ]) throws Exception{
             String x=args[0];
             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(result);
          }   
    }

    2.在 網絡編程與安全-4 基礎上,客戶端將後綴表達式明文的MD5值算出,發往服務器:
    String valueMD5 = MD5.numberMD5 (plainText);
    3.服務器接受客戶端MD5值,與自身算出的後綴表達式明文的MD5值比較,若相同則繼續:

    String clicetValueMD5 = in.readUTF ();
    String valueMD5 = MD5.numberMD5 (plainText);
    if (!clicetValueMD5.equals (valueMD5)) {
        return;
    }

    截圖

    image.png
    image.png
    image.png


    6、實驗過程當中遇到的問題以及解決方案

    1. 問題:實際運用 DH 算法時,使用密鑰超過 JDK 默認密鑰大小。

    ---使用甲方本地密鑰對數據進行加密---
    Exception in thread "main" java.security.InvalidKeyException: Illegal key size or default parameters
        at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1026)
        at javax.crypto.Cipher.implInit(Cipher.java:801)
        at javax.crypto.Cipher.chooseProvider(Cipher.java:864)
        at javax.crypto.Cipher.init(Cipher.java:1249)
        at javax.crypto.Cipher.init(Cipher.java:1186)
        at DHCoder.encrypt(DHCoder.java:101)
        at DHTest.main(DHTest.java:56)
    
    Process finished with exit code 1

    解決方案:

    由於某些國家的進口管制限制,Java發佈的運行環境包中的加解密有必定的限制。好比默認不容許256位密鑰的AES加解密,解決方法就是修改策略文件。
    下載與JDK或JRE對應版本的jce文件包,當前機器的jdk爲1.8,因此下載jce_policy-8.zip。
    將解壓獲得的兩個jar文件 local_policy.jarUS_export_policy.jar 也放到 %JDK_HOME%\jre\lib\security 下,進行替換。
    jce_policy-8.zip下載連接

    2. 問題:經過 out.writeUTF(); 傳輸後沒法正確接收,變爲亂碼

    客戶端:

    //經過 `Base64` 的方法 `encodeBase64String ();` 將數組轉化爲字符串類型
    String tempKey1 = Base64.encodeBase64String (publicKey1);
    //out發送信息
    out.writeUTF (tempKey1);

    服務器:

    ......
     //由客戶端的公鑰產生的密鑰對
    String tempKey1 = in.readUTF ();
    byte [] publicKey1 = tempKey1.getBytes ();
    System.out.println("客戶端公鑰:/n"+Base64.encodeBase64String(publicKey1));
    Map<String,Object> keyMap2=DH.initKey(publicKey1);
    ......

    報錯:密鑰格式不對。

    解決方案:

    由於 out.writeUTF(); in.readUTF (); 傳輸的數據類型爲 String ,而不是 byte [] 數組,因此不可用 getBytes (); 方法來提取。
    要使用 Base64 方法 encodeBase64String (); 的對應的方法 decodeBase64 (tempKey1); 來轉換數據類型。

    String tempKey1 = in.readUTF ( );
    byte[] publicKey1 = Base64.decodeBase64 (tempKey1);
    System.out.println ("客戶端公鑰:/n" + Base64.encodeBase64String (publicKey1));
    Map <String, Object> keyMap2 = DH.initKey (publicKey1);

    7、代碼連接

    碼雲倉庫:YogileOne https://gitee.com/Yogile/YogileOne.git

    碼雲項目網頁連接:https://gitee.com/Yogile/YogileOne/tree/master/str/exam_5


    8、 PSP

    步驟 耗時 百分比
    需求分析 10min 7.7%
    設計 30min 23.1%
    代碼實現 50min 38.5%
    測試 30min 23.1%
    分析總結 10min 7.6%
    相關文章
    相關標籤/搜索