实验五:实验报告

实验五:实验报告

课程:程序设计与数据结构

实验内容

任务一

编写MyBC.java实现中缀表达式转后缀表达式的功能

编写MyDC.java实现从上面功能中获取的表达式中实现后缀表达式求值的功能

package lib;

import java.util.ArrayList;
import java.util.Stack;

/**
 * Created by dell on 2017/6/6.
 */
public class MyDC {
    public static String main(String exp) {
        ArrayList<String> expLst = getStringList(exp);
        ArrayList<String> DClst = getRPN(expLst);
        StringBuffer result = new StringBuffer();
        for(String i:DClst)result.append(i + " ");
        return result.toString();

    }

    private static ArrayList<String> getStringList(String str) {
        ArrayList<String> result = new ArrayList<String>();
        String num = "";
        for (String item : str.split(" ")) result.add(item);
        return result;
    }
    private static ArrayList<String> getRPN(ArrayList<String> inOrderList) {
        ArrayList<String> RPN = new ArrayList<String>();
        Stack<String> stack = new Stack<String>();
        for (String item : inOrderList) {
            if (Character.isDigit(item.charAt(0))) RPN.add(item);
            else {
                while (!stack.isEmpty() && compare(stack.peek(), item)) RPN.add(stack.pop());
                stack.push(item);
            }
        }
        while (!stack.isEmpty()) RPN.add(stack.pop());
        return RPN;
    }
    private static boolean compare(String peek, String cur) {
        if ("*".equals(peek) && ("/".equals(cur) || "*".equals(cur) || "+".equals(cur) || "-".equals(cur))) {
            return true;
        } else if ("/".equals(peek) && ("/".equals(cur) || "*".equals(cur) || "+".equals(cur) || "-".equals(cur))) {
            return true;
        } else if ("+".equals(peek) && ("+".equals(cur) || "-".equals(cur))) {
            return true;
        } else if ("-".equals(peek) && ("+".equals(cur) || "-".equals(cur))) {
            return true;
        }
        return false;
    }
}

任务二

结对编程:一人负责客户端,另一人负责服务器

注意责任归宿,要会通过测试证明自己没有问题

基于Java Socket实现客户端/服务器功能,传输方式用TCP

客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式通过网络发送给服务器

服务器接收到后缀表达式,调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端

客户端显示服务器发送过来的结果
2017-06-06 (2).png

任务三

客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密后通过网络把密文发送给服务器

服务器接收到后缀表达式表达式后,进行解密(和客户端协商密钥,可以用数组保存),然后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端

其他要求同任务二
2017-06-06 (3).png
Crypt.java

package aes;

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

/**
 * Created by dell on 2017/6/6.
 */
public class Crypt {
    public static byte[] encrypt(String content, String password) {
        try {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");
            kgen.init(128, new SecureRandom(password.getBytes()));
            SecretKey secretKey = kgen.generateKey();
            byte[] enCodeFormat = secretKey.getEncoded();
            SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
            Cipher cipher = Cipher.getInstance("AES");// 创建密码器
            byte[] byteContent = content.getBytes("utf-8");
            cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
            byte[] result = cipher.doFinal(byteContent);
            return result; // 加密
        } 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 byte[] decrypt(byte[] content, String password) {
        try {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");
            kgen.init(128, new SecureRandom(password.getBytes()));
            SecretKey secretKey = kgen.generateKey();
            byte[] enCodeFormat = secretKey.getEncoded();
            SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] result = cipher.doFinal(content);
            return 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 parseByte2HexStr(byte buf[]) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < buf.length; i++) {
            String hex = Integer.toHexString(buf[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }

    public static byte[] parseHexStr2Byte(String hexStr) {
        if (hexStr.length() < 1)
            return null;
        byte[] result = new byte[hexStr.length()/2];
        for (int i = 0;i< hexStr.length()/2; i++) {
            int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16);
            int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }
}

Client.java

package aes;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

/*
 * 客户端
 */
public class Client {

    public static void main(String[] args) {
        try {
            String psw = "ncaiuscibabc";
            Scanner sc = new Scanner(System.in);
            Socket socket=new Socket("localhost", 8765);
            OutputStream os=socket.getOutputStream();
            PrintWriter pw=new PrintWriter(os);
            String encryption = Crypt.parseByte2HexStr(Crypt.encrypt(sc.nextLine(),psw));
            pw.write(encryption);
            pw.flush();
            socket.shutdownOutput();
            InputStream is=socket.getInputStream();
            BufferedReader br=new BufferedReader(new InputStreamReader(is));
            String info=null;
            while((info=br.readLine())!=null){
                System.out.println(info);
            }
            br.close();
            is.close();
            pw.close();
            os.close();
            socket.close();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Server.java

package aes;

import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;


public class Server {
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(8765);
            Socket socket = null;
            System.out.println("Init Successfully");
            while(true){
                socket=serverSocket.accept();
                ServerThread serverThread=new ServerThread(socket);
                serverThread.start();
                InetAddress address=socket.getInetAddress();
                System.out.println("Connect IP:"+address.getHostAddress());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

ServerThread.java

package aes;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import lib.MyDC;

/*
 * 服务器线程处理类
 */
public class ServerThread extends Thread {
    // 和本线程相关的Socket
    Socket socket = null;
    final String psw = "ncaiuscibabc";
    public ServerThread(Socket socket) {
        this.socket = socket;
    }

    //线程执行的操作,响应客户端的请求
    public void run(){
        InputStream is = null;
        InputStreamReader isr = null;
        BufferedReader br = null;
        OutputStream os = null;
        PrintWriter pw = null;
        try {
            //获取输入流,并读取客户端信息
            is = socket.getInputStream();
            isr = new InputStreamReader(is);
            br = new BufferedReader(isr);
            String exp = MyDC.main(new String(Crypt.decrypt(Crypt.parseHexStr2Byte(br.readLine()),psw)));
            socket.shutdownInput();//关闭输入流
            //获取输出流,响应客户端的请求
            os = socket.getOutputStream();
            pw = new PrintWriter(os);
            pw.write(exp);
            pw.flush();//调用flush()方法将缓冲输出
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            //关闭资源
            try {
                if(pw!=null)
                    pw.close();
                if(os!=null)
                    os.close();
                if(br!=null)
                    br.close();
                if(isr!=null)
                    isr.close();
                if(is!=null)
                    is.close();
                if(socket!=null)
                    socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

任务四

客户端和服务器用DH算法进行3DES或AES算法的密钥交换

其他要求同任务三
2017-06-07 (1).png

任务五

服务器接收到后缀表达式表达式后,进行解密,解密后计算明文的MD5值,和客户端传来的MD5进行比较,一致则调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
2017-06-07 (1).png

package dh;

import sun.misc.BASE64Encoder;

import java.io.*;
import java.math.BigInteger;
import java.net.*;
import java.security.*;
import java.security.spec.*;
import java.util.*;

/*
 * 客户端
 */
public class Client {



    public static String connect(String msg){
        try{
            Socket socket=new Socket("localhost", 8766);
            OutputStream os=socket.getOutputStream();
            PrintWriter pw=new PrintWriter(os);
            pw.write(msg);
            pw.flush();
            socket.shutdownOutput();
            InputStream is = socket.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            String result = br.readLine();
            br.close();
            is.close();
            pw.close();
            os.close();
            socket.close();
            return result;
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    public static void main(String[] args){
        String headers[] = {"Key&&","Exp&&","&&"};
        String content;
        byte[] publicKey1 = null,privateKey1 = null,key=null;
        try {
            Map<String, Object> keyMap1 = DHCoder.initKey();
            publicKey1 = DHCoder.getPublicKey(keyMap1);
            privateKey1 = DHCoder.getPrivateKey(keyMap1);
        }catch (Exception e){
            e.printStackTrace();
        }
        content = headers[0] + Parser.parseByte2HexStr(publicKey1);
        byte[] publicKey2 = Parser.parseHexStr2Byte(connect(content));
        try {
            key = DHCoder.getSecretKey(publicKey2,privateKey1);
        }catch (Exception e){
            e.printStackTrace();
        }
        try {
            Scanner sc = new Scanner(System.in);
            String exp = sc.nextLine();
            MessageDigest md = MessageDigest.getInstance("MD5");
            BASE64Encoder base64en = new BASE64Encoder();
            byte[] encrypt = DHCoder.encrypt(exp.getBytes(),key);

            content = headers[1] + Parser.parseByte2HexStr(encrypt) + headers[2] + base64en.encode(md.digest(exp.getBytes("utf-8")));;
            String en_result = connect(content);
            String result = new String(DHCoder.decrypt(Parser.parseHexStr2Byte(en_result),key));
            System.out.println(result);
        }catch (Exception e){
            e.printStackTrace();
        }

















    }
}
package dh;

import java.security.*;
import java.security.spec.*;
import java.util.*;
import javax.crypto.*;
import javax.crypto.interfaces.*;
import javax.crypto.spec.*;

public abstract class DHCoder {
    /**
     * 非对称加密密钥算法
     */
    private static final String KEY_ALGORITHM = "DH";
    /**
     * 本地密钥算法,即对称加密密钥算法
     * 可选DES、DESede或者AES
     */
    private static final String SELECT_ALGORITHM = "DESede";
    /**
     * 密钥长度
     */
    private static final int KEY_SIZE = 512;
    //公钥
    private static final String PUBLIC_KEY = "DHPublicKey";
    //私钥
    private static final String PRIVATE_KEY = "DHPrivateKey";

    /**
     * 初始化甲方密钥
     * @return Map 甲方密钥Map
     * @throws Exception
     */
    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>(2);
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }

    /**
     * 初始化乙方密钥
     * @param key 甲方公钥
     * @return Map 乙方密钥Map
     * @throws Exception
     */
    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 dhParameterSpec = ((DHPublicKey)pubKey).getParams();
        //实例化密钥对生成器
        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>(2);
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }

    /**
     * 加密
     * @param data 待加密数据
     * @param key 密钥
     * @return byte[] 加密数据
     * @throws Exception
     */
    public static byte[] encrypt(byte[] data, byte[] key) throws Exception{
        //生成本地密钥
        SecretKey secretKey = new SecretKeySpec(key, SELECT_ALGORITHM);
        //数据加密
        Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        return cipher.doFinal(data);
    }

    /**
     * 解密
     * @param data 待解密数据
     * @param key 密钥
     * @return byte[] 解密数据
     * @throws Exception
     */
    public static byte[] decrypt(byte[] data, byte[] key) throws Exception{
        //生成本地密钥
        SecretKey secretKey = new SecretKeySpec(key, SELECT_ALGORITHM);
        //数据揭秘
        Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        return cipher.doFinal(data);
    }

    /**
     * 构建密钥
     * @param publicKey 公钥
     * @param privateKey 私钥
     * @return byte[] 本地密钥
     * @throws Exception
     */
    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(SELECT_ALGORITHM);
        return secretKey.getEncoded();
    }

    /**
     * 取得私钥
     * @param keyMap 密钥Map
     * @return byte[] 私钥
     * @throws Exception
     */
    public static byte[] getPrivateKey(Map<String, Object> keyMap) throws Exception{
        Key key = (Key) keyMap.get(PRIVATE_KEY);
        return key.getEncoded();
    }

    /**
     * 取得公钥
     * @param keyMap 密钥Map
     * @return byte[] 公钥
     * @throws Exception
     */
    public static byte[] getPublicKey(Map<String, Object> keyMap) throws Exception{
        Key key = (Key) keyMap.get(PUBLIC_KEY);
        return key.getEncoded();
    }
}
package dh;

/**
 * Created by dell on 2017/6/7.
 */
public class Parser {
    public static String parseByte2HexStr(byte buf[]) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < buf.length; i++) {
            String hex = Integer.toHexString(buf[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }

    public static byte[] parseHexStr2Byte(String hexStr) {
        if (hexStr.length() < 1)
            return null;
        byte[] result = new byte[hexStr.length()/2];
        for (int i = 0;i< hexStr.length()/2; i++) {
            int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16);
            int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }
}

package dh;

import lib.MyDC;
import sun.misc.BASE64Encoder;

import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.MessageDigest;
import java.util.Map;


public class Server {
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(8766);
            Socket socket = null;
            System.out.println("Init Successfully");
            byte[] key = null;
            while(true){
                socket = serverSocket.accept();
                InputStream is = null;
                InputStreamReader isr = null;
                BufferedReader br = null;
                OutputStream os = null;
                PrintWriter pw = null;
                byte[] publicKey1 = null,privateKey1 = null;
                try {
                    is = socket.getInputStream();
                    isr = new InputStreamReader(is);
                    br = new BufferedReader(isr);
                    String content = br.readLine();
                    if(content.charAt(0)=='K'){
                        String publicKey = content.split("&&")[1];
                        System.out.println(publicKey);
                        Map<String, Object> keyMap1 = DHCoder.initKey();
                        publicKey1 = DHCoder.getPublicKey(keyMap1);
                        privateKey1 = DHCoder.getPrivateKey(keyMap1);
                        key = DHCoder.getSecretKey(Parser.parseHexStr2Byte(publicKey),privateKey1);
                        socket.shutdownInput();
                        os = socket.getOutputStream();
                        pw = new PrintWriter(os);
                        if(publicKey1!= null)pw.write(Parser.parseByte2HexStr(publicKey1));
                    }
                    else {
                        byte[] en_exp = Parser.parseHexStr2Byte(content.split("&&")[1]);
                        String exp = new String(DHCoder.decrypt(en_exp,key));
                        MessageDigest md = MessageDigest.getInstance("MD5");
                        BASE64Encoder base64en = new BASE64Encoder();
                        String check = content.split("&&")[2];
                        String hash = base64en.encode(md.digest(exp.getBytes("utf-8")));
                        String ans = MyDC.main(exp);
                        socket.shutdownInput();
                        os = socket.getOutputStream();
                        pw = new PrintWriter(os);
                        if(check.equals(hash) && ans!= null)pw.write(Parser.parseByte2HexStr(DHCoder.encrypt(ans.getBytes(),key)));
                        else pw.write("Hash Failed");
                    }
                    pw.flush();
                } catch (Exception e) {
                    e.printStackTrace();
                }finally{
                    try {
                        if(pw!=null)
                            pw.close();
                        if(os!=null)
                            os.close();
                        if(br!=null)
                            br.close();
                        if(isr!=null)
                            isr.close();
                        if(is!=null)
                            is.close();
                        if(socket!=null)
                            socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                InetAddress address=socket.getInetAddress();
                System.out.println("Connect IP:"+address.getHostAddress());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

实验中遇到的问题

DH算法中客户端和服务端需要两次通信才能生成结果,但是示例代码都是进行无状态通信,在一个循环体内接受两次通信再进行下一次循环来解决。但是实际上可以把Key存储在数据库中来解决,因为这种方法是不支持多客户端的。

实验心得

学习了Java网络编程和密码学的相关知识。

posted @ 2017-06-19 13:16  20162308马平川  阅读(238)  评论(0编辑  收藏  举报