zoukankan      html  css  js  c++  java
  • 2017-2018-1 20155326《信息安全系统设计基础》 实验五 通讯协议设计

    2017-2018-1 20155326《信息安全系统设计基础》 实验五 通讯协议设计

    实验任务一

    在Ubuntu中完成 http://www.cnblogs.com/rocedu/p/5087623.html 中的作业

    基于Socket实现TCP通信,一人实现服务器,一人实现客户端

    研究OpenSSL算法,测试对称算法中的AES,非对称算法中的RSA,Hash算法中的MD5

    选用合适的算法,基于混合密码系统实现对TCP通信进行机密性、完整性保护。

    学有余力者,对系统进行安全性分析和改进。

    实验过程

    OpenSSL的简介

    • OpenSSL 是一个安全套接字层密码库,囊括主要的密码算法、常用的密钥和证书封装管理功能及SSL协议,并提供丰富的应用程序供测试或其它目的使用。OpenSSL 是一个SSL协议的开源实现,采用C语言作为开发语言,具备了跨平台的能力,支持Unix/Linux、Windows、Mac OS等多种平台。

    • OpenSSL整个软件包大概可以分成三个主要的功能部分:SSL协议库、应用程序以及密码算法库。OpenSSL的目录结构自然也是围绕这三个功能部分进行规划的。

    • 作为一个基于密码学的安全开发包,OpenSSL提供的功能相当强大和全面,囊括了主要的密码算法、常用的密钥和证书封装管理功能以及SSL协议,并提供了丰富的应用程序供测试或其它目的使用。

    • OpenSSL的应用程序已经成为了OpenSSL重要的一个组成部分,其重要性恐怕是OpenSSL的开发者开始没有想到的。如OpenCA,就是完全使用OpenSSL的应用程序实现的。OpenSSL的应用程序是基于OpenSSL的密码算法库和SSL协议库写成的,所以也是一些非常好的OpenSSL的API使用范例,读懂所有这些范例,你对OpenSSL的API使用了解就比较全面了,当然,这也是一项锻炼你的意志力的工作。

    • OpenSSL的应用程序提供了相对全面的功能,在相当多的人看来,OpenSSL已经为自己做好了一切,不需要再做更多的开发工作了,所以,他们也把这些应用程序称为OpenSSL的指令。OpenSSL的应用程序主要包括密钥生成、证书管理、格式转换、数据加密和签名、SSL测试以及其它辅助配置功能。

    Linux下OpenSSL的安装

    • 在https://www.openssl.org/source/中安装OpenSSL最新版本。

    • 将压缩包在虚拟机中解压

    • 依次输入如下命令进行安装

      ./config
      make
      make test
      make install

    过程图如下:

    Linux下OpenSSL的使用

    • 通过man openssl查看帮助文档。

    • 编写一个测试代码test_openssl.c:

    • 使用gcc -o test_openssl test_openssl.c -L/usr/local/ssl/lib -lcrypto -ldl -lpthread命令编译。

    在这个过程中,出现了错误,提示没有openssl/evp.h,在网上查找了相应教程,输入sudo apt-get install libssh-dev后即可。

    • 生成“test_openssl”可执行文件,运行程序,并执行echo $?,结果打印0,测试结果表明安装成功。

    Linux的SOCKET编程

    • TCP/IP协议族包括运输层、网络层、链路层,而socket所在位置如图,Socket是应用层与TCP/IP协议族通信的中间软件抽象层。

    • socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。Socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭).说白了Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

    • 服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。其中使用到的函数有:socket()函数、bind()函数、listen()、connect()函数、accept()函数、read()、write()函数等。

    • 我和20155320组队,他实现客户端,我实现的是服务器,以下是我的代码:
    
    #include<stdio.h>  
    #include<stdlib.h>  
    #include<string.h>  
    #include<errno.h>  
    #include<sys/types.h>  
    #include<sys/socket.h>  
    #include<netinet/in.h>  
    #define DEFAULT_PORT 8000  
    #define MAXLINE 4096  
    int main(int argc, char** argv)  
    {  
        int    socket_fd, connect_fd;  
        struct sockaddr_in     servaddr;  
        char    buff[4096];  
        int     n;  
        //初始化Socket  
        if( (socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){  
        printf("create socket error: %s(errno: %d)
    ",strerror(errno),errno);  
        exit(0);  
        }  
        //初始化  
        memset(&servaddr, 0, sizeof(servaddr));  
        servaddr.sin_family = AF_INET;  
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);//IP地址设置成INADDR_ANY,让系统自动获取本机的IP地址。  
        servaddr.sin_port = htons(DEFAULT_PORT);//设置的端口为DEFAULT_PORT  
      
        //将本地地址绑定到所创建的套接字上  
        if( bind(socket_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){  
        printf("bind socket error: %s(errno: %d)
    ",strerror(errno),errno);  
        exit(0);  
        }  
        //开始监听是否有客户端连接  
        if( listen(socket_fd, 10) == -1){  
        printf("listen socket error: %s(errno: %d)
    ",strerror(errno),errno);  
        exit(0);  
        }  
        printf("======waiting for client's request======
    ");  
        while(1){  
    //阻塞直到有客户端连接,不然多浪费CPU资源。  
            if( (connect_fd = accept(socket_fd, (struct sockaddr*)NULL, NULL)) == -1){  
            printf("accept socket error: %s(errno: %d)",strerror(errno),errno);  
            continue;  
        }  
    //接受客户端传过来的数据  
        n = recv(connect_fd, buff, MAXLINE, 0);  
    //向客户端发送回应数据  
        if(!fork()){ /*紫禁城*/  
            if(send(connect_fd, "Hello,you are connected!
    ", 26,0) == -1)  
            perror("send error");  
            close(connect_fd);  
            exit(0);  
        }  
        buff[n] = '';  
        printf("recv msg from client: %s
    ", buff);  
        close(connect_fd);  
        }  
        close(socket_fd);  
    }
    
    

    运行截图如下:

    通过openssl测试密码算法

    • enc中可以指定的对称加密算法指令可能并没有以单独指令的形式存在,所以我们常用enc方式来调用加密算法。

    测试AES

    • 此测试例子是使用的openssl库中提供的EVP系列函数对数据进行解密的一个测试,选择的算法为:AES128,加密模式为:CBC。

    • 命令行输入密码123456 :openssl enc -aes-128-cbc -in lmc.txt -out out.txt -pass pass:123456 ;

    • 文件输入,密码123456:echo 123456 > passwd.txt openssl enc -aes-128-cbc -in lmc.txt -out out.txt -pass file:passwd.txt;

    • 从标准输入输入:openssl enc -aes-128-cbc -in lmc.txt -out out.txt -pass stdin。

    测试RSA

    • RSA是一个非对称加密算法。简单说来,非对称加密算法就是说加密解密一个文件需要有两个密钥,一个用来加密,为公钥,一个用来解密,为私钥。证书可以用来授权公钥的使用。

    • openssl的rsa加密,其中主要涉及利用公钥和密钥加解密文件,没有涉及对证书的操作。

    • 首先生成一个rsa私钥:

    这里-out指定生成文件的。需要注意的是这个文件包含了公钥和密钥两部分,也就是说这个文件即可用来加密也可以用来解密。后面的1024是生成密钥的长度。

    • openssl可以将这个文件中的公钥提取出来:

    -in指定输入文件,-out指定提取生成公钥的文件名。至此,我们手上就有了一个公钥,一个私钥(包含公钥)。现在可以将用公钥来加密文件了。

    • 我在目录中创建一个hello的文本文件,然后利用此前生成的公钥加密文件:

    -in指定要加密的文件,-inkey指定密钥,-pubin表明是用纯公钥文件加密,-out为加密后的文件。

    • 解密文件:

    -in指定被加密的文件,-inkey指定私钥文件,-out为解密后的文件。

    • 查看解密文件

    至此,一次加密解密的过程结束。

    生成rsa私钥文件:openssl genrsa -out rsaprivatekey.pem 1024。
    生成公钥文件,指明输出文件是公钥文件openssl rsa -in rsaprivatekey.pem -pubou -out rsapubckey.pem。
    用公钥匙rsapubckey.pem加密文件plain.txt,输出到文件hello.en:openssl rsautl -encrypt -in plain.txt -inkey rsapubckey.pem -pubin -out hello.en;
    使用私钥匙rsaprivatekey.pem解密密文hello.en,输出到文件hello.de:openssl rsautl -decrypt -in hello.en -inkey rsaprivatekey.pem -pubin -out hello.de

    测试 MD5

    实验任务二:

    在Ubuntu中实现对实验二中的“wc服务器”通过混合密码系统进行防护

    OpenSSL流程和函数介绍

    • 首先初始化
      int SSL_Library_init (void);

    • 接着选择会话协议和创建会话环境

    目前支持的会话协议包括:TLSv1.0, SSLv2, SSLv3, SSLv2/v3。
    OpenSSL中一个会话的环境称为“CTX”,申请CTX的函数是:

    SSL_CTX *SSL_CTX_new (SSL_METHOD *method);
    

    其中method就是会话协议,比如SSLv2/v3的client,则传入函数调用的返回值:

    const SSL_METHOD *SSLv23_client_method (void);
    
    • 接下来是设置CTX的属性,比如制定证书验证方式:

      int SSL_CTX_set_verify (SSL_CTX ctx,
      int mode,
      int (
      verify_callback),
      int (X509_STROE_CTX *));

    • 加载CA证书:

      SSL_CTX_load_varify_location (SSL_CTX *ctx, const char *Cafile, const char *Capath);

    • 加载用户私钥:

      SSL_CTX_use_Private_file (SSL_CTX *ctx, const char *file, int type);

    • 加载用户证书:

      SSL_CTX_use_certificate_file (SSL_CTX *ctx, const char *file, int type);

    • 验证私钥和证书是否相等

      int SSL_CTX_check_private_key (SSL_CTX *ctx);

    • 建立SSL套接字
      SSL *SSL_new (SSL_CTX *ctx);

    • 使用socket绑定SSL套接字:

      int SSL_set_fd (SSL *ssl, int fd);
      int SSL_set_rfd (SSL *ssl, int fd); // 只读
      int SSL_set_wfd (SSL *ssl, int fd); // 只写

    注意:上述三个函数成功时返回TRUE,失败时返回FALSE

    • 完成SSL握手

      int SSL_connect (SSL *ssl); // 用于client
      int SSL_accept (SSL *ssl); // 用于client

    • 从SSL套接字中提取对方的证书信息
      X509 *SSL_get_peer_certificate (SSL *ssl);

    • 获取证书所有者的名字:

      X509_NAME *X509_get_subject_name (X509 *a);

    • 数据传输

      int SSL_read (SSL *ssl, void *buf, int num);
      int SSL_write (SSL *ssl, const void *buf, int num);

    • 结束SSL通信

    • 关闭SSL套接字

      int SSL_shitdown (SSL *ssl);

    • 释放SSL套接字

      void SSL_free (SSL *ssl);

    • 释放SSL会话

      void SSL_CTX_free (SSL_CTX *ctx);

    • 下面大致的伪代码说明了调用SSL的一整个流程:

    Client端:

    
    ctx = SSL_CTX_new (SSLv23_client_method());
    ssl = SSL_new (ctx);
    fd = socket ();
    connect ();
    SSL_set_fd (ssl, fd);
    SSL_connect (ssl);
    SSL_write ();
    
    

    Server端:

    
    ctx = SSL_CTX_new (SSLv23_server_method());
    ssl = SSL_new (ctx);
    fd = socket ();
    bind ();
    listen ();
    accept ();
    SSL_set_fd (ssl, fd);
    SSL_accept (ssl);
    SSL_read ();
    
    
    • 具体代码见码云

    码云链接

    运行结果

    实验中遇到的问题及解决方法

    • 使用gcc -o test_openssl test_openssl.c -L/usr/local/ssl/lib -lcrypto -ldl -lpthread命令编译。

    在这个过程中,出现了错误,提示没有openssl/evp.h,在网上查找了相应教程,输入sudo apt-get install libssh-dev后即可。

    参考文献

    ubuntu php编译安装 openssl/evp.h: 没有那个文件或目录
    Linux下OpenSSL的安装与使用
    Linux的SOCKET编程详解
    使用openssl中的EVP通用加密算法接口的之--解密测试例子
    利用openssl进行RSA加密解密
    OpenSSL流程和函数介绍

  • 相关阅读:
    五种常见的 PHP 设计模式
    转载:php header下载乱码 空格 问题
    PHP程序员最常犯的11个MySQL错误
    启迪人心:10个的有关编程的至理名言
    如何使用搜索技巧来成为一名高效的程序员
    随机验证码
    产生sql表中表示字段, 实现自增列
    在当前页面弹出对话框
    读取页面传入的URL值
    Sql临时表
  • 原文地址:https://www.cnblogs.com/lmc1998/p/8040473.html
Copyright © 2011-2022 走看看