zoukankan      html  css  js  c++  java
  • 2018-2019-20175307 实验五《网络编程与安全》实验报告

    第一个任务

    这个任务是要将输入的中缀表达式转换为后缀表达式,并用老师已经写好的后缀表达式进行计算,所以任务的难点就在于如何将中缀表达式转化为后缀表达式。对于这个难点,娄老师要求写成MyBC.java来进行操作。
    因为第一次遇见这样的问题,所以果断转向百度求助,不出所料,有两篇博客,一篇为另一篇为
    讲到了中缀表达式转后缀表达式的规则:
    首先将各种运算符(包括括号)的优先级排列如下(数字越大,优先级越高):
    1:(
    2:+ -
    3:* /
    4:)
    对输入的中缀表达式从左到右遍历:
    1)如果遇到数字,直接添加到后缀表达式末尾;
    2)如果遇到运算符+、-、*、/:
    先判断栈是否为空。若是,则直接将此运算符压入栈。若不是,则查看当前栈顶元素。若栈顶元素优先级大于或等于此操作符级别,则弹出栈顶元素,将栈顶元素添加到后缀表达式中,并继续进行上述判断。如果不满足上述判断或者栈为空,将这个运算符入栈。要注意的是,经过上述步骤,这个运算符最终一定会入栈。
    3)如果遇到括号:
    如果是左括号,直接入栈。如果是右括号,弹出栈中第一个左括号前所有的操作符,并将左括号弹出。(右括号别入栈)。
    4)字符串遍历结束后,如果栈不为空,则弹出栈中所有元素,将它们添加到后缀表达式的末尾,直到栈为空。

    所以我就按照c++代码,写出了java的MyBC

     while(i<length){
                if(ch[i]>='0'&&ch[i]<='9'){
                    st+=ch[i];
                }
                else if(ch[i]=='+'||ch[i]=='-'||ch[i]=='*'||ch[i]=='/'){
                    if(stack.empty()){
                        temp = String.valueOf(ch[i]);
                        stack.push(temp);
                    }
                    else{
                        while (!stack.empty()){
                            tem=stack.peek().charAt(0);
                            if(getPriority(tem)>=getPriority(ch[i])){
                                st+=tem;
                                stack.pop();
                            }
                            else{
                                break;
                            }
                        }
                        temp = String.valueOf(ch[i]);
                        stack.push(temp);
                    }
                }
                else{
                    if(ch[i]=='('){
                        temp = String.valueOf(ch[i]);
                        stack.push(temp);
                    }
                    else{
                        while(!stack.peek().equals(String.valueOf('('))){
                            tem = stack.peek().charAt(0);
                            st+=tem;
                            stack.pop();
                        }
                        stack.pop();
                    }
                }
                i++;
            }
    

    但是出现了一些问题,就是在用MyDC的输入格式和MyBC输出格式不一样的情况。
    因为没有注意到MyDC的输入的字符串中每个有效字符是由一个空格作为间隔的,所以在MyBC将中缀表达式转为后缀表达式的时候,并没有做处理,所以会导致最终MyDC计算结果为0的情况。
    处理方法是在给st输出字符串添加元素的时候,多添加一个空格。
    st+=tem;
    替换为
    st=st+tem+" ";

    st+=ch[i];
    替换为
    st=st+ch[i]+" ";
    就可以正确计算了。

    第二个任务是

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

    1. 基于Java Socket实现客户端/服务器功能,传输方式用TCP
    2. 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式通过网络发送给服务器
    3. 服务器接收到后缀表达式,调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
    4. 客户端显示服务器发送过来的结果
    5. 上传测试结果截图和码云链接

    因为团队项目恰好也有关服务器和客户端,所以基于Java Socket实现客户端/服务器功能,传输方式用TCP对我来说,并不是很难。在这里我直接用的是java书上的最简单的例子。
    然后在客户端增加输入功能,然后将输入的中缀表达式通过任务一的MyDC转换为MyBC,最终传输给服务器端,服务器端在接收到后缀表达式侯,进行MyBC的计算,最终得到答案。
    但是还是出现了一个问题
    java writeUtf出现了java.lang.NullPointerException
    后来发现是忘记没有实例化~new DataOutputStream
    增加

    in = new DataInputStream(client.getInputStream());out = new DataOutputStream(client.getOutputStream());
    

    之后就可以正常使用了。

    第三个任务是

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

    1. 基于Java Socket实现客户端/服务器功能,传输方式用TCP
      2. 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密后通过网络把密文发送给服务器
    2. 服务器接收到后缀表达式表达式后,进行解密(和客户端协商密钥,可以用数组保存),然后调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
    3. 客户端显示服务器发送过来的结果
    4. 上传测试结果截图和码云链接

    因为我之前已经写过DES的算法了,所以这次选的是AES算法挑战一下,但是出现了很多的问题。
    javax.crypto.BadPaddingException: Given final block not properly padded
    其中一个就是这个问题。
    百度之后果然由大神已经解决了这个问题。
    博客链接
    和一篇文库

    kgen.init(128, new SecureRandom(key.getBytes()));
    

    替换为

    kgen.init(128, random);
    

    就可以了,具体问题不是很懂。

    第四个任务是

    密钥分发结对编程:1人负责客户端,一人负责服务器

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

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

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

    4. 客户端显示服务器发送过来的结果

    5. 上传测试结果截图和码云链接

    密钥交换算法——DH
    简述
    1976年,W.Diffie和M.Hellman在发表的论文中提出了公钥加密算法思想,但当时并没有给出具体的实施方案,原因在于没有找到单向函数(也就是消息摘要算法),但在该论文中给出了通信双方通过信息交换协商密钥的算法,即Diffie-Hellman密钥交换算法(简称为DH算法)。该算法的目的在于让消息的收发双方可以在安全的条件下交换密钥,以备后续加密/解密使用。因此,DH算法是第一个密钥协商算法,但仅能用于密钥分配,不能用于加密或者解密消息。

    DH密钥交换算法的安全性基于有限域上的离散对数难题。基于这种安全性,通过DH算法进行密钥分配,使得消息的收发双方可以安全地交换一个密钥,再通过这个密钥对数据进行加密和解密处理。
    其实该算法的原理和上一部分中简单乘法及其类似,只是获取da或者db不是简单的方程式了,而是涉及到对数运算。对数运算被认为是“难”的,这个难建立在目前为止没有找到一个快速计算对数的算法,数学上没有证明这个算法是否存在。
    因为之前密码学数学基础可上讲过a^b mod n的快速算法,所以我就按照这个算法去计算。
    public static int quick  (int a,int b,int m){
        int ans=a;
        String bin = binaryToDecimal(b);
        char[] chr = bin.toCharArray();
        for(int i=1;i<bin.length();i++){
            if(chr[i]==1){
                ans = (ans*ans*a)%m;
            }
            else {
                ans = (ans*ans)%m;
            }
        }
        return ans;
    }
    返回值便是a^b mod n。
    还是按照socket方法,将生成的密钥作为下一个阶段AES的密钥,就可以保证接下来过程的正确性了。
    


    第五个任务是

    完整性校验结对编程:1人负责客户端,一人负责服务器
    0. 注意责任归宿,要会通过测试证明自己没有问题

    1. 基于Java Socket实现客户端/服务器功能,传输方式用TCP
      2. 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密通过网络把密文和明文的MD5値发送给服务器
    2. 客户端和服务器用DH算法进行3DES或AES算法的密钥交换
    3. 服务器接收到后缀表达式表达式后,进行解密,解密后计算明文的MD5值,和客户端传来的MD5进行比较,一致则调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
    4. 客户端显示服务器发送过来的结果
    5. 上传测试结果截图和码云链接

    具体来说文件的MD5值就像是这个文件的“数字指纹”。每个文件的MD5值是不同的,如果任何人对文件做了任何改动,其MD5值也就是对应的“数字指纹”就会发生变化。比如下载服务器针对一个文件预先提供一个MD5值,用户下载完该文件后,用我这个算法重新计算下载文件的MD5值,通过比较这两个值是否相同,就能判断下载的文件是否出错,或者说下载的文件是否被篡改了。MD5实际上一种有损压缩技术,压缩前文件一样MD5值一定一样,反之MD5值一样并不能保证压缩前的数据是一样的。在密码学上发生这样的概率是很小的,所以MD5在密码加密领域有一席之地。但是专业的黑客甚至普通黑客也可以利用MD5值实际是有损压缩技术这一原理,将MD5的逆运算的值作为一张表俗称彩虹表的散列表来破解密码。
    虽然MD5更多的是用在文件的校对上,但是也可以用在我们这个后缀表达式的信息上。
    我的理解就是应该先用DH算法进行密钥的交换,生成双方一致的密钥,依此作为AES加密和解密的密钥。
    MD5计算的是后缀表达式的值,保证后缀表达式的消息完整性。
    因为我记得娄老师之前写过一篇密码学的博客,所以直接用的娄老师的代码。

    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);
             }
    
    ![](https://img2018.cnblogs.com/blog/1613137/201905/1613137-20190531082507910-2019602431.png)
    ![](https://img2018.cnblogs.com/blog/1613137/201905/1613137-20190531082513816-964509183.png)
  • 相关阅读:
    DB2错误代码
    Hbase配置中出现的问题总结
    自定义控件三部曲之动画篇(一)——alpha、scale、translate、rotate、set的xml属性及用法
    关于CoordinatorLayout与Behavior的一点分析
    Android UI:看看Google官方自定义带旋转动画的ImageView-----RotateImageView怎么写(附 图片淡入淡...)
    android之官方下拉刷新组件SwipeRefreshLayout
    Android改变图片颜色的自定义控件
    android 之修改图片的某一颜色值
    Android动态修改图片颜色的实现方式分析
    Android WebView常见问题及解决方案汇总
  • 原文地址:https://www.cnblogs.com/gsc20175307/p/10953164.html
Copyright © 2011-2022 走看看