• 2018-2019 1 20165203 实验五 通用协议设计


    2018-2019 1 20165203 实验五 通用协议设计

    OpenSSL学习

    • 定义:OpenSSL是为网络通信提供安全及数据完整性的一种安全协议,囊括了主要的密码算法、常用的密钥和证书封装管理功能以及SSL协议,并提供了丰富的应用程序供测试或其它目的使用。
    • 基本功能:
      • 密码算法库
      • SSL协议库
      • 应用程序
    • 其中:密码算法库是一个强大完整的密码算法库,它是OpenSSL的基础部分,也是很值得一般密码安全技术人员研究的部分,它实现了目前大部分主流的密码算法和标准。主要包括对称算法、非对称算法、散列算法、数字签名和认证、X509数字证书标准、PKCS12、PKCS7等标准。其他两个功能部分SSL协议和应用程序都是基于这个库开发的。
    • 在密码算法库的基础上实现的,SSL协议部分完全实现和封装了SSL协议的三个版本和TLS协议。使用协议库,完全可以建立一个SSL服务器和SSL客户端。
    • 应用程序是基于密码算法库和SSL协议库实现的命令,熟悉OpenSSL可以从使用这些应用程序开始。应用程序覆盖了密码技术的应用,主要包括了各种算法的加密程序和各种类型密钥的产生程序(如RSA、Md5、Enc等等)、证书签发和验证程序(如Ca、X509、Crl等)、SSL连接测试程序(如S_client和S_server等)以及其它的标准应用程序(如Pkcs12和Smime等)。

    任务一

    两人一组
    基于Socket实现TCP通信,一人实现服务器,一人实现客户端
    研究OpenSSL算法,测试对称算法中的AES,非对称算法中的RSA,Hash算法中的MD5
    选用合适的算法,基于混合密码系统实现对TCP通信进行机密性、完整性保护。
    学有余力者,对系统进行安全性分析和改进。  
    
    
    • 实验步骤:
      1.安装Openssl。
    • 在虚拟机的Linux系统中前往Openssl官网,下载openssl-master.zip
    • 下载完毕后,利用unzip openssl-master.zip命令解压,解压后如图所示。

    • 利用如下命令进行安装。
    $ ./config
    $ make
    $ make test
    $ make install  
    
    • 安装完毕即可。

    2.进行安装测试。

    • 编写一个测试代码test_openssl.c
    #include <stdio.h>
    #include <openssl/evp.h>
    
    int main(){
        OpenSSL_add_all_algorithms();
        return 0;
    }  
    
    • 使用命令gcc -o test_openssl test_openssl.c -L/usr/local/ssl/lib -lcrypto -ldl -lpthread进行编译,生成“test_openssl”可执行文件,运行。接下来,执行echo $?,打印出的结果是0,则代表运行成功。

    • 命令的学习:

    -L选项——指定链接库的文件夹地址;
    -lcrypto——导入OpenSSL所需包;
    -ldl选项——加载动态库;
    -lpthread选项——链接POSIX thread库    
    

    3.基于Socket实现TCP通信,实现服务器和客户端的通信。连接后,如图所示。

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

    • AES

    编写代码aes.c

    
    #include <memory.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <openssl/aes.h>
    #pragma comment(lib,"libeay32.lib")
    int main(int argc, char **argv)
    {
        unsigned char buf[512];
        unsigned char buf2[512];
        unsigned char buf3[512];
        unsigned char aes_keybuf[32];
        memset(buf,1,sizeof(buf));    
        memset(buf,0,sizeof(buf2));    
        memset(buf,0,sizeof(buf3));
        memset(aes_keybuf,0,sizeof(aes_keybuf));
        AES_KEY aeskey;
        AES_set_encrypt_key(aes_keybuf,256,&aeskey);
        for(int i=0;i<sizeof(buf);i+=16)
        AES_encrypt(buf+i,buf2+i,&aeskey);
        AES_set_decrypt_key(aes_keybuf,256,&aeskey);
        for(int i=0;i<sizeof(buf);i+=16)
        AES_decrypt(buf2+i,buf3+i,&aeskey);
        if(memcmp(buf,buf3,sizeof(buf))==0)
            printf("test success
    ");
        else
            printf("test fail
    ");
    }  
    
    

    使用gcc aes.c -o aes -L/usr/local/ssl/lib -lcrypto -ldl -lpthread进行编译,并运行,运行完结果如图所示。

    • RSA算法

    编写rsa.c

    
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<openssl/rsa.h>
    #include<openssl/pem.h>
    #include<openssl/err.h>
    #define OPENSSLKEY "test.key"
    #define PUBLICKEY "test_pub.key"
    #define BUFFSIZE 1024
    char* my_encrypt(char *str,char *path_key);//加密
    char* my_decrypt(char *str,char *path_key);//解密
    int main(void){
        char *source="I'm 20165203xyx who is a nice student.";
        char *ptr_en,*ptr_de;
        printf("source is    :%s
    ",source);
        ptr_en=my_encrypt(source,PUBLICKEY);
        printf("after encrypt:%s
    ",ptr_en);
        ptr_de=my_decrypt(ptr_en,OPENSSLKEY);
        printf("after decrypt:%s
    ",ptr_de);
        if(ptr_en!=NULL){
            free(ptr_en);
        }   
        if(ptr_de!=NULL){
            free(ptr_de);
        }   
        return 0;
    }
    char *my_encrypt(char *str,char *path_key){
        char *p_en;
        RSA *p_rsa;
        FILE *file;
        int flen,rsa_len;
        if((file=fopen(path_key,"r"))==NULL){
            perror("open key file error");
            return NULL;    
        }   
        if((p_rsa=PEM_read_RSA_PUBKEY(file,NULL,NULL,NULL))==NULL){
            ERR_print_errors_fp(stdout);
            return NULL;
        }   
        flen=strlen(str);
        rsa_len=RSA_size(p_rsa);
        p_en=(unsigned char *)malloc(rsa_len+1);
        memset(p_en,0,rsa_len+1);
        if(RSA_public_encrypt(rsa_len,(unsigned char *)str,(unsigned char*)p_en,p_rsa,RSA_NO_PADDING)<0){
            return NULL;
        }
        RSA_free(p_rsa);
        fclose(file);
        return p_en;
    }
    char *my_decrypt(char *str,char *path_key){
        char *p_de;
        RSA *p_rsa;
        FILE *file;
        int rsa_len;
        if((file=fopen(path_key,"r"))==NULL){
            perror("open key file error");
            return NULL;
        }
        if((p_rsa=PEM_read_RSAPrivateKey(file,NULL,NULL,NULL))==NULL){
            ERR_print_errors_fp(stdout);
            return NULL;
        }
        rsa_len=RSA_size(p_rsa);
        p_de=(unsigned char *)malloc(rsa_len+1);
        memset(p_de,0,rsa_len+1);
        if(RSA_private_decrypt(rsa_len,(unsigned char *)str,(unsigned char*)p_de,p_rsa,RSA_NO_PADDING)<0){
            return NULL;
        }
        RSA_free(p_rsa);
        fclose(file);
        return p_de;
    }  
    

    同样的方法编译运行,得到结果,成功。

    • MD5算法。
    #define _GNU_SOURCE
    
    #include <stdio.h>
    
    #include <string.h>
    
    #include <stdlib.h>
    
    #include <errno.h>
    
    #include <ctype.h>
    
    #include "openssl/md5.h"
    
    MD5_CTX  md5_ctx;
    static int MD5mod(const char* str, int length, int mod){
    
        char sign[16] = {0};
    
        MD5_Init(&md5_ctx);
    
        MD5_Update(&md5_ctx, str, length);
    
        MD5_Final(sign, &md5_ctx);
    
        printf("digest:%s
    ",sign);
    
        int sum = 0;
    
        for (int i=0; i < 16; i ++) {
    
            sum += (sign[i]&0xff);
    
        }
    
        int offset = sum % mod;
    
        return offset;
    
    }
    
    int main(int argc, char** argv)
    
    {
    
        if( argc < 4){
    
            fprintf(stderr, "%s num infile outfile
    ", argv[0]);
    
            exit(-1);
    
        }
    
        int num = atoi(argv[1]) ;
    
        if( num <= 0){
    
            fprintf(stderr, "ERROR: num error: %s
    ", argv[1]);
    
            exit(-1);
    
        }
    
        FILE* in = fopen(argv[2], "r");
    
        if( in == NULL){
    
            perror("fopen");
    
            fprintf(stderr, "ERROR: infile error: %s
    ", argv[2]);
    
            exit(-1);
    
        }
        FILE** OUT = (FILE**)malloc(sizeof(FILE*) * num);
    
        for(int i=0; i<num; ++i){
    
            char buf[256] = {0};
    
            sprintf(buf, "%s_%d", argv[3], i);
    
            OUT[i] = fopen(buf, "w");
    
            if( OUT[i] == NULL){
    
                perror("fopen");
    
                fprintf(stderr, "ERROR: infile error: %s
    ", argv[2]);
    
                exit(-1);
    
            }
    
        }
        size_t len = 0;
        ssize_t read;
        char * line = NULL;
    
        while ((read = getline(&line, &len, in)) != -1) {
    
            int  klen = 0;
    
            while( klen < read ){
    
                if( isspace( *(line+klen)) ) break;
    
                klen++;
            }
    
         //   char id[256]={0};
    
         //   strncpy(id, line, klen);
    
         //   printf("id=%s	klen=%d	read=%ld	line=%s", id, klen, read, line);
    
            fprintf(OUT[MD5mod(line, klen, num)], "%s", line);
    
        }
    
        if(line) free(line);
        return 0;
    }  
    

    编译运行,如图所示。

    任务二

    在Ubuntu中实现对实验二中的“wc服务器”通过混合密码系统进行防护
    提交测试截图  
    
    1. 学习wc服务器模式如下。

    1. 编写代码如下。

    server.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <string.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <sys/socket.h>
    #include <sys/wait.h>
    #include <unistd.h>
    #include <arpa/inet.h>
    #include <openssl/ssl.h>
    #include <openssl/err.h>
     #include <openssl/evp.h>
    
    
    #define MAXBUF 1024
    
    int main(int argc, char **argv)
    {
        int sockfd, new_fd;
        socklen_t len;
        struct sockaddr_in my_addr, their_addr;
        unsigned int myport, lisnum;
        char buf[MAXBUF + 1];
        SSL_CTX *ctx;
    
        if (argv[1])
            myport = atoi(argv[1]);
        else
            myport = 5227;
    
        if (argv[2])
            lisnum = atoi(argv[2]);
        else
            lisnum = 2;
    
        /* SSL 库初始化 */
        SSL_library_init();
        /* 载入所有 SSL 算法 */
        OpenSSL_add_all_algorithms();
        /* 载入所有 SSL 错误消息 */
        SSL_load_error_strings();
        /* 以 SSL V2 和 V3 标准兼容方式产生一个 SSL_CTX ,即 SSL Content Text */
        ctx = SSL_CTX_new(SSLv23_server_method());
        /* 也可以用 SSLv2_server_method() 或 SSLv3_server_method() 单独表示 V2 或 V3标准 */
        if (ctx == NULL) {
            ERR_print_errors_fp(stdout);
            exit(1);
        }
        /* 载入用户的数字证书, 此证书用来发送给客户端。 证书里包含有公钥 */
        if (SSL_CTX_use_certificate_file(ctx, argv[3], SSL_FILETYPE_PEM) <= 0) {
            ERR_print_errors_fp(stdout);
            exit(1);
        }
        /* 载入用户私钥 */
        if (SSL_CTX_use_PrivateKey_file(ctx, argv[4], SSL_FILETYPE_PEM) <= 0){
            ERR_print_errors_fp(stdout);
            exit(1);
        }
        /* 检查用户私钥是否正确 */
        if (!SSL_CTX_check_private_key(ctx)) {
            ERR_print_errors_fp(stdout);
            exit(1);
        }
    
        /* 开启一个 socket 监听 */
        if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
            perror("socket");
            exit(1);
        } else
            printf("socket created
    ");
    
        bzero(&my_addr, sizeof(my_addr));
        my_addr.sin_family = PF_INET;
        my_addr.sin_port = htons(myport);
        my_addr.sin_addr.s_addr = INADDR_ANY;
    
        if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr))
            == -1) {
            perror("bind");
            exit(1);
        } else
            printf("binded
    ");
    
        if (listen(sockfd, lisnum) == -1) {
            perror("listen");
            exit(1);
        } else
            printf("begin listen
    ");
    
        while (1) {
            SSL *ssl;
            len = sizeof(struct sockaddr);
            /* 等待客户端连上来 */
            if ((new_fd =
                 accept(sockfd, (struct sockaddr *) &their_addr,
                        &len)) == -1) {
                perror("accept");
                exit(errno);
            } else
                printf("server: got connection from %s, port %d, socket %d
    ",
                       inet_ntoa(their_addr.sin_addr),
                       ntohs(their_addr.sin_port), new_fd);
    
            /* 基于 ctx 产生一个新的 SSL */
            ssl = SSL_new(ctx);
            /* 将连接用户的 socket 加入到 SSL */
            SSL_set_fd(ssl, new_fd);
            /* 建立 SSL 连接 */
            if (SSL_accept(ssl) == -1) {
                perror("accept");
                close(new_fd);
                break;
            }
    
            /* 开始处理每个新连接上的数据收发 */
            bzero(buf, MAXBUF + 1);
            strcpy(buf, "hello");
            /* 发消息给客户端 */
            len = SSL_write(ssl, buf, strlen(buf));
    
            if (len <= 0) {
                printf
                    ("消息'%s'发送失败!错误代码是%d,错误信息是'%s'
    ",
                     buf, errno, strerror(errno));
                goto finish;
            } else
                printf("消息'%s'发送成功,共发送了%d个字节!
    ",
                       buf, len);
    
            bzero(buf, MAXBUF + 1);
            /* 接收客户端的消息 */
            len = SSL_read(ssl, buf, MAXBUF);
            if (len > 0)
                printf("接收消息成功:'%s',共%d个字节的数据
    ",
                       buf, len);
            else
                printf
                    ("消息接收失败!错误代码是%d,错误信息是'%s'
    ",
                     errno, strerror(errno));
            /* 处理每个新连接上的数据收发结束 */
          finish:
            /* 关闭 SSL 连接 */
            SSL_shutdown(ssl);
            /* 释放 SSL */
            SSL_free(ssl);
            /* 关闭 socket */
            close(new_fd);
        }
        /* 关闭监听的 socket */
        close(sockfd);
        /* 释放 CTX */
        SSL_CTX_free(ctx);
        return 0;
    }  
    

    talent.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <string.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <sys/socket.h>
    #include <sys/wait.h>
    #include <unistd.h>
    #include <arpa/inet.h>
    #include <openssl/ssl.h>
    #include <openssl/err.h>
     #include <openssl/evp.h>
    
    
    #define MAXBUF 1024
    
    int main(int argc, char **argv)
    {
        int sockfd, new_fd;
        socklen_t len;
        struct sockaddr_in my_addr, their_addr;
        unsigned int myport, lisnum;
        char buf[MAXBUF + 1];
        SSL_CTX *ctx;
    
        if (argv[1])
            myport = atoi(argv[1]);
        else
            myport = 5227;
    
        if (argv[2])
            lisnum = atoi(argv[2]);
        else
            lisnum = 2;
    
        /* SSL 库初始化 */
        SSL_library_init();
        /* 载入所有 SSL 算法 */
        OpenSSL_add_all_algorithms();
        /* 载入所有 SSL 错误消息 */
        SSL_load_error_strings();
        /* 以 SSL V2 和 V3 标准兼容方式产生一个 SSL_CTX ,即 SSL Content Text */
        ctx = SSL_CTX_new(SSLv23_server_method());
        /* 也可以用 SSLv2_server_method() 或 SSLv3_server_method() 单独表示 V2 或 V3标准 */
        if (ctx == NULL) {
            ERR_print_errors_fp(stdout);
            exit(1);
        }
        /* 载入用户的数字证书, 此证书用来发送给客户端。 证书里包含有公钥 */
        if (SSL_CTX_use_certificate_file(ctx, argv[3], SSL_FILETYPE_PEM) <= 0) {
            ERR_print_errors_fp(stdout);
            exit(1);
        }
        /* 载入用户私钥 */
        if (SSL_CTX_use_PrivateKey_file(ctx, argv[4], SSL_FILETYPE_PEM) <= 0){
            ERR_print_errors_fp(stdout);
            exit(1);
        }
        /* 检查用户私钥是否正确 */
        if (!SSL_CTX_check_private_key(ctx)) {
            ERR_print_errors_fp(stdout);
            exit(1);
        }
    
        /* 开启一个 socket 监听 */
        if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
            perror("socket");
            exit(1);
        } else
            printf("socket created
    ");
    
        bzero(&my_addr, sizeof(my_addr));
        my_addr.sin_family = PF_INET;
        my_addr.sin_port = htons(myport);
        my_addr.sin_addr.s_addr = INADDR_ANY;
    
        if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr))
            == -1) {
            perror("bind");
            exit(1);
        } else
            printf("binded
    ");
    
        if (listen(sockfd, lisnum) == -1) {
            perror("listen");
            exit(1);
        } else
            printf("begin listen
    ");
    
        while (1) {
            SSL *ssl;
            len = sizeof(struct sockaddr);
            /* 等待客户端连上来 */
            if ((new_fd =
                 accept(sockfd, (struct sockaddr *) &their_addr,
                        &len)) == -1) {
                perror("accept");
                exit(errno);
            } else
                printf("server: got connection from %s, port %d, socket %d
    ",
                       inet_ntoa(their_addr.sin_addr),
                       ntohs(their_addr.sin_port), new_fd);
    
            /* 基于 ctx 产生一个新的 SSL */
            ssl = SSL_new(ctx);
            /* 将连接用户的 socket 加入到 SSL */
            SSL_set_fd(ssl, new_fd);
            /* 建立 SSL 连接 */
            if (SSL_accept(ssl) == -1) {
                perror("accept");
                close(new_fd);
                break;
            }
    
            /* 开始处理每个新连接上的数据收发 */
            bzero(buf, MAXBUF + 1);
            strcpy(buf, "hello");
            /* 发消息给客户端 */
            len = SSL_write(ssl, buf, strlen(buf));
    
            if (len <= 0) {
                printf
                    ("消息'%s'发送失败!错误代码是%d,错误信息是'%s'
    ",
                     buf, errno, strerror(errno));
                goto finish;
            } else
                printf("消息'%s'发送成功,共发送了%d个字节!
    ",
                       buf, len);
    
            bzero(buf, MAXBUF + 1);
            /* 接收客户端的消息 */
            len = SSL_read(ssl, buf, MAXBUF);
            if (len > 0)
                printf("接收消息成功:'%s',共%d个字节的数据
    ",
                       buf, len);
            else
                printf
                    ("消息接收失败!错误代码是%d,错误信息是'%s'
    ",
                     errno, strerror(errno));
            /* 处理每个新连接上的数据收发结束 */
          finish:
            /* 关闭 SSL 连接 */
            SSL_shutdown(ssl);
            /* 释放 SSL */
            SSL_free(ssl);
            /* 关闭 socket */
            close(new_fd);
        }
        /* 关闭监听的 socket */
        close(sockfd);
        /* 释放 CTX */
        SSL_CTX_free(ctx);
        return 0;
    }  
    
    1. 编译运行。
    • 使用gcc -o server server.c -I /usr/local/ssl/include -L/usr/local/ssl/lib -lssl -lcrypto -ldl -lpthread编译server.c
    • 使用gcc -o telent telent.c -I /usr/local/ssl/include -L/usr/local/ssl/lib -lssl -lcrypto -ldl -lpthread
    • 使用openssl genrsa -out privkey.pem 1024 openssl req -new -x509 -key privkey.pem -out CAcert.pem -days 1095来生产私钥和证书。
    • 使用./server 5203 1 CAcert.pem privkey.pem ./telent 127.0.0.1 5203来运行。

    运行后如图所示。

    实验中出现的问题及解答。

    Q1:安装openssl时出现如图所示问题。

    A1:将“openssl-master”文件夹下的“libcrypto.a”“libssl.a”放在/usr/local/ssl/lib目录下(注意使用sudo权限),编译时链接这个目录即可。

    Q2:编译任务2时出现如图所示问题。

    A2:要使用命令gcc -o server server.c -I /usr/local/ssl/include -L/usr/local/ssl/lib -lssl -lcrypto -ldl -lpthread来进行相应的库链接。

    实验感想

    本次实验我们主要学习了Openssl的主要内容结构和用法,该实验还与计算机网络和密码学的相关知识结合起来,更符合我们信息安全专业的特点,也学到了很多知识。
    本学期该课的实验就要结束了,但是学习知识的脚步要永远进行着,生命不息,学习不止,只有不断学习新知识才会一直进步。

  • 相关阅读:
    2015-05-06前端开发总结
    深入了解 Flexbox 伸缩盒模型
    Sublime text3 快捷方式(windows平台)
    移动web最简洁的滑动效果Swipe JS(适合初学者)
    谈响应式web设计代码实现
    经验分享:多屏复杂动画CSS技巧三则
    css3 animation动画效果解析
    移动H5前端性能优化指南
    php codeigniter (CI) oracle 数据库配置-宋正河整理
    jquery图片裁切+PHP文件上传
  • 原文地址:https://www.cnblogs.com/20165203-xyx/p/10126214.html
Copyright © 2020-2023  润新知