2018-2019-2 20175233 實驗五實驗報告

網絡編程與安全-1


任務詳情

兩人一組結對編程:結對對象 20175223 姚明宇html

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

MyBC.java
import java.util.*;
import java.util.stream.Collectors;
import java.lang.Integer;
public class MyBC{
    private static final Map
   
   
   

  
   
  basic = new HashMap 
 
   
     (); static { basic.put('-', 1); basic.put('+', 1); basic.put('*', 2); basic.put('/', 2); basic.put('(', 0); } //中綴表達式 轉 後綴表達式 public static String toSuffix(String infix){ List 
    
      queue = new ArrayList 
     
       (); List 
      
        stack = new ArrayList 
       
         (); 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;
import java.lang.Integer;

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; } } 
    

  
MyDCTest.java
//import junit.framework.TestCase;
import java.util.Scanner;

public class MyDCTest   {
    public static void main(String[] args) {
        String expression, again;
        int result;
        try {
            Scanner in = new Scanner (System.in);

            do {
                MyDC evaluator = new MyDC ( );
                System.out.println ("Enter a valid postfix expression: ");
                expression = in.nextLine ( );

                result = evaluator.evaluate (expression);
                System.out.println ( );
                System.out.println ("That expression equals " + result);

                System.out.print ("Evaluate another expression [Y/N]? ");
                again = in.nextLine ( );
                System.out.println ( );
            }
            while (again.equalsIgnoreCase ("y"));
        } catch (Exception IOException) {
            System.out.println ("Input exception reported");
        }
    }
}
MyBCTest.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 str2;
        Scanner reader = new Scanner (System.in);
        System.out.println ("IEnter a expression: ");
        inExpression = reader.nextLine ();
        str2 = mybc.toSuffix (inExpression);
        System.out.println ("str2: " +str2);
        System.out.println ("result: " +mydc.evaluate(str2));
    }
}

實驗截圖:

1-1.png

1-2.png


網絡編程與安全-2


任務詳情

結對編程:20175233嚴順堯負責客戶端,20175223姚明宇負責服務器java

  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.png

2.png


網絡編程與安全-3


任務詳情

  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;
import java.lang.*;
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;
    }
}
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";
            //輸入密文,32字符密鑰
            String miwen = AES.ecodes(str,key);

            out.writeUTF (miwen);
            //in讀取信息,堵塞狀態
            String temp = in.readUTF ( );

            String answer = in.readUTF ( );

            Thread.sleep (500);
        } catch (Exception e) {
            System.out.println ("服務器已斷開" + e);
        }
    }
}
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);
            temp = MyBC.toSuffix (mingwen);
            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.png

2.png


網絡編程與安全-4


任務詳情

  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
   
   
   

  
   
  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 
 
   
     keyMap=new HashMap 
    
      (); keyMap.put(PUBLIC_KEY, publicKey); keyMap.put(PRIVATE_KEY, privateKey); return keyMap; } /** * 初始化乙方密鑰 * @param key 甲方密鑰(這個密鑰是經過第三方途徑傳遞的) * @return Map 乙方密鑰的Map * */ public static Map 
     
       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 
      
        keyMap=new HashMap 
       
         (); 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 
        
          keyMap){ Key key=(Key)keyMap.get(PRIVATE_KEY); return key.getEncoded(); } /** * 取得公鑰 * @param keyMap 密鑰map * @return byte[] 公鑰 * */ public static byte[] getPublicKey(Map 
         
           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 
          
            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 
           
             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讀取信息,堵塞狀態,111111
            cipherText = in.readUTF ( );
            System.out.println ("服務器收到客戶的後綴表達式密文:\n" + cipherText + "\n");


            //由甲方的公鑰產生的密鑰對
            // in讀取信息,堵塞狀態,2222222
            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發送信息,333333 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); } } } 

  

實驗截圖1.png

2.png


網絡編程與安全-5


任務詳情

  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.*;
public class Md5{
    public static String numberMD5(String plainTest) throws Exception{
        String x=plainTest;
        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;
    }
}
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讀取信息,堵塞狀態,111111
            cipherText = in.readUTF ( );
            System.out.println ("服務器收到客戶的後綴表達式密文:\n" + cipherText + "\n");


            //由甲方的公鑰產生的密鑰對
            // in讀取信息,堵塞狀態,2222222
            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發送信息,333333 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); String md5zhi2 =Md5.numberMD5(plainText); String md5zhi1 =in.readUTF ( ); if(md5zhi2.equals(md5zhi1))System.out.println ("\n能解密"); else System.out.println ("\n不能解密"); 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); } } } 

  
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);
            String md5zhi1 =Md5.numberMD5(plainText);
            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)); out.writeUTF(md5zhi1); //接受乙方的計算結果 answer = in.readUTF ( ); System.out.println ("\n**計算由服務器進行**\n\n客戶收到服務器的計算結果:\n" + answer); Thread.sleep (500); } catch (Exception e) { System.out.println ("服務器已斷開" + e); } } } 

  

實驗截圖

1.png

2.png


問題

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

客戶端:git

//經過 `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);
......

報錯:密鑰格式不對。express

解決方案:

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

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