• 实验五:实验报告


    实验五:实验报告

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

    实验内容

    任务一

    编写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网络编程和密码学的相关知识。

  • 相关阅读:
    iphoneX 兼容
    app 判断网络状态
    app 版本升级
    express 安装
    app打开QQ与陌生人聊天
    app项目中几个常用的cordvoa插件
    axios请求拦截器和相应拦截器
    vue中MD5+base64加密
    想啥写啥
    react canvas圆环动态百分比
  • 原文地址:https://www.cnblogs.com/pingch/p/7048237.html
Copyright © 2020-2023  润新知