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);
相关文章
相关标签/搜索