20155213 实验五《网络编程与安全》实验报告

20155213 实验五《网络编程与安全》实验报告

实验内容

  1. 了解计算机网络基础
  2. 掌握Java Socket编程
  3. 理解混合密码系统
  4. 掌握Java 密码技术相关API的使用

实验步骤与结果

任务一

  1. 参考http://www.cnblogs.com/rocedu/p/6766748.html#SECDSA
  2. 结对实现中缀表达式转后缀表达式的功能 MyBC.java
  3. 结对实现从上面功能中获取的表达式中实现后缀表达式求值的功能,调用MyDC.java
  • 栈的介绍
    • 只允许在表尾插入和删除的线性表
    • 允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom)
    • 后进先出 (LIFO)
  • 后缀式的运算规则
    • 运算符在式中出现的顺序恰为表达式的运算顺序;
    • 每个运算符和在它之前出现且紧靠它的两个操作数构成一个最小表达式。
  • 原表达式求得后缀式
    • 设立一个栈,存放运算符,首先栈为空;
      编译程序从左到右扫描原表达式,若遇到操作 数,直接输出,并输出一个空格作为两个操作 数的分隔符;
    • 若遇到运算符,则与栈顶比较,比栈顶级别高 则进栈,否则退出栈顶元素并输出,然后输出 一个空格作分隔符;
    • 若遇到左括号,进栈;若遇到右括号,则一直 退栈输出,直到退到左括号止。
    • 当栈变成空时,输出的结果即为后缀表达式。

  • 代码难点解决
    • 如何压栈

while (tokenizer.hasMoreTokens())
        {
            token = tokenizer.nextToken();

            //如果是运算符,调用isOperator
            if (this.isOperator(token))
            {
                if(token.charAt(0)==')')
                    while (Nch!='(')
                    {
                        Nch=this.stack.pop();
                        if(Nch!='(')
                            Nextexpr=Nextexpr+" "+Nch;
                    }
                Nch=' ';
                ch=this.stack.pop();
                this.stack.push(ch);
                if(('*'==token.charAt(0)&&(ch=='+'||ch=='-'))||('*'==token.charAt(0)&&ch==' ')||('*'==token.charAt(0)&&ch=='(')||
                        ('/'==token.charAt(0)&&(ch=='+'||ch=='-'))||('/'==token.charAt(0)&&ch==' ')||('/'==token.charAt(0)&&ch=='(')
                        ||('-'==token.charAt(0)&&(ch=='('||ch==' '))
                        ||('+'==token.charAt(0)&&(ch=='('||ch==' '))
                        || '('==token.charAt(0))
                    this.stack.push(token.charAt(0));
                else if(token.charAt(0)!=')'){
                    Nextexpr=Nextexpr+" "+this.stack.pop();
                    ch=this.stack.pop();
                    this.stack.push(ch);
                    if(!(('*'==token.charAt(0)&&(ch=='+'||ch=='-'))||('*'==token.charAt(0)&&ch==' ')||('*'==token.charAt(0)&&ch=='(')||
                            ('/'==token.charAt(0)&&(ch=='+'||ch=='-'))||('/'==token.charAt(0)&&ch==' ')||('/'==token.charAt(0)&&ch=='(')
                            ||('-'==token.charAt(0)&&(ch=='('||ch==' '))
                            ||('+'==token.charAt(0)&&(ch=='('||ch==' '))
                            || '('==token.charAt(0))){
                        Nextexpr=Nextexpr+" "+this.stack.pop();
                    }

                    this.stack.push(token.charAt(0));
                }
            }
            else//如果是操作数
            {
                Nextexpr=Nextexpr+" "+token;
            }

        }
        while(!this.stack.empty())
        {
            Nextexpr=Nextexpr+" "+this.stack.pop();
        }

  • 运行截图

任务二

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

  1. 注意责任归宿,要会通过测试证明自己没有问题
  2. 基于Java Socket实现客户端/服务器功能,传输方式用TCP
  3. 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式通过网络发送给服务器
  4. 服务器接收到后缀表达式,调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
  5. 客户端显示服务器发送过来的结果
  • socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过"套接字"向网络发出请求或者应答网络请求

  • 在调用了socket之后其实也就只需要IP和端口号要和服务器一致就好

  • 我负责的是客户端

  • 端口号和IP设置代码


            Socket socket = new Socket("192.168.43.252",5204);
    System.out.println("客户端启动成功");

  • 运行截图

任务三

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

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

  • 密码介绍
  • 对称密码(symmetric cryptography)是指在加密和解密时使用同一密钥的方式。
  • 公钥密码(public-key cryptography)则是指在加密和解密时使用不同密钥的方式,公钥密码又称为非对称密码(asymmetric cryptography)。
  • 本实验用到的对称密码算法3DES
  • 具体步骤参考java密码学
  • 运行截图

任务四

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

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

  • DH算法是建立在DH公钥和私钥的基础上的,A需要和B共享密钥时,A和B各自生成DH公钥和私钥,公钥对外公布而私钥各自秘密保存。本实例将介绍Java中如何创建并部署DH公钥和私钥,以便后面一小节利用它创建共享密钥。

  • 建立两个目录A和B,模拟需要秘密通信的A、B双方,由于DH算法需要A和B各自生成DH公钥和私钥,因此在这两个目录下都拷贝编译后文件Key_DH。

  • 首先由A创建自己的公钥和私钥,即在A目录下输入“java Key_DH Apub.dat Apri.dat”运行程序,这时在目录A下将产生文件Apub.dat和Apri.dat,前者保存着A的公钥,后者保存着A的私钥。

  • 然后由B创建自己的公钥和私钥,即在B目录下输入“java Key_DH Bpub.dat Bpri.dat”运行程序,这时在目录B下将产生文件Bpub.dat和Bpri.dat,前者保存着B的公钥,后者保存着B的私钥。

  • 最后发布公钥,A将Apub.dat拷贝到B目录,B将Bpub.dat拷贝到A的目录。
    这样,A、B双方的DH公钥和私钥已经创建并部署完毕。

  • 运行截图

任务五

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

  1. 基于Java Socket实现客户端/服务器功能,传输方式用TCP
  2. 客户端让用户输入中缀表达式,然后把中缀表达式调用MyBC.java的功能转化为后缀表达式,把后缀表达式用3DES或AES算法加密通过网络把密文和明文的MD5値发送给服务器
  3. 客户端和服务器用DH算法进行3DES或AES算法的密钥交换
  4. 服务器接收到后缀表达式表达式后,进行解密,解密后计算明文的MD5值,和客户端传来的MD5进行比较,一致则调用MyDC.java的功能计算后缀表达式的值,把结果发送给客户端
  5. 客户端显示服务器发送过来的结果
  • MD5介绍
import java.security.*;
public class DigestPass{
     public static void main(String args[ ]) throws Exception{
         String x=args[0];
         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);
         }
         System.out.println(result);
      }   
}
  • 运行截图

任务六

  • Android 开发:
  • 客户端功能用Android实现,完成有加分
  • 这是我和20155303一起利用三天假期完成的,特别感谢她的帮助以及细心(´▽`ʃƪ);
  • 这里的客户端就是手机上的APP,而服务器依旧是IDEA上运行的服务器端
  • 手机上的具体实现代码
package com.example.dell.webapp;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.net.UnknownHostException;

public class MainActivity extends AppCompatActivity {
    private TextView text1;
    private Button but1;
    private TextView text2;
    private EditText edit1;
    private final String DEBUG_TAG="mySocketAct";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        text1 = (TextView)findViewById(R.id.text1);
        text2 = (TextView)findViewById(R.id.text2);
        but1 = (Button)findViewById(R.id.but1);
        edit1 = (EditText) findViewById(R.id.edit);

        but1.setOnClickListener(new Button.OnClickListener()
        {
            @Override
            public void onClick(View v){
                Socket socket = null;
                String mesg = edit1.getText().toString();
                Log.e("dddd","set id");
                text1.setText(mesg);
                MyBC mybc=new MyBC();
                MyDC mydc=new MyDC();
                String Np="";
                String mesg1=mybc.evaluate(mesg);

                for(int i=2;i<mesg1.length();i++)
                    Np+=mesg1.charAt(i);

                int a= mydc.evaluate(Np);
                String str=a+"";
                text2.setText(str);




                try{
                     //text2.setText("结果");
                    socket = new Socket("172.16.2.107",5216);
                    PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);

                    mesg1 = mybc.evaluate(mesg);
                    //
                    for(int i=2;i<mesg1.length();i++)
                        Np+=mesg1.charAt(i);

                    out.println(Np);
                    out.flush();

                    BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                    String mstr = br.readLine();
                    if(mstr!=null){

                        text2.setText(mstr);
                    }else{
                        text2.setText("数据错误");
                    }
                    out.close();
                    br.close();
                    socket.close();
                }catch (UnknownHostException e){
                    e.printStackTrace();
                }catch (IOException e){
                    e.printStackTrace();
                }catch (Exception e){
                    Log.e(DEBUG_TAG, e.toString());
                }
            }
        });
    }
}
  • 运行截图

出现的问题及解决

  • 问题
  • 客户端的显示:
    can not listen to:java.net.SocketException: Connection reset

  • 服务器端显示:Error.javax.crypto.BadPaddingException: Given final block not properly padded

  • 问题解决
  • 这往往是从客户端传来的密文不符合编码要求导致的,在查阅了很多相关问题解决的网站后,总结出,在传送密文时,需要将编码改为ISO-8859-1,而不是一惯的UTF8,改完后就可以正常运行了;

实验体会

这次实验让我对结对编程有了更深的认识,两个人一起可以很好的各自发挥自己的长处,可以更加有效,更加快速的解决问题,真的感谢20155303同学的帮助。

码云链接

参考文献

PSP(Personal Software Process)时间

步骤 耗时(min) 百分比
需求分析 20 20
设计 30 30
代码实现 30 30
测试 10 10
分析总结 10 10
原文地址:https://www.cnblogs.com/elevator/p/6933358.html