• 2017-2018-1 20155201 实验五 通讯协议设计


    2017-2018-1 20155201 实验五 固件程序设计

    一、实验内容

    1. 安装OpenSSL环境,并编写测试代码验证无误
    2. 研究OpenSSL算法,测试对称算法中的AES,非对称算法中的RSA,Hash算法中的MD5
    3. 在Ubuntu中实现对实验二中的“wc服务器”通过混合密码系统进行防护

    二、实验步骤

    1. 安装OpenSSL环境,并编写测试代码验证无误

      • 官网的下载地址下载zip包并解压

      • 在命令行中输入

      ./config
      make
      sudo make install
      

      等待安装完即可。其中需要注意的一行是库文件被复制到哪个文件夹里面了

      • 编写一个测试代码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/lib(路径) -lcrypto -ldl -lpthread
      > ./test_openssl
      > echo $?
      
    2. 研究OpenSSL算法,测试对称算法中的AES,非对称算法中的RSA,Hash算法中的MD5

      • 对称加密:对称加密需要使用的标准命令为 enc
      openssl enc -ciphername [-in filename] [-out filename] [-pass arg] [-e] [-d] [-a/-base64]
         [-A] [-k password] [-kfile filename] [-K key] [-iv IV] [-S salt] [-salt] [-nosalt] [-z] [-md]
         [-p] [-P] [-bufsize number] [-nopad] [-debug] [-none] [-engine id]
         
      -in filename:指定要加密的文件存放路径
      
      -out filename:指定加密后的文件存放路径
      
      -salt:自动插入一个随机数作为文件内容加密,默认选项
      
      -e:可以指明一种加密算法,若不指的话将使用默认加密算法
      
      -d:解密,解密时也可以指定算法,若不指定则使用默认算法,但一定要与加密时的算法一致
      
      -a/-base64:使用-base64位编码格式
      
      • AES:
      openssl enc -aes-128-cbc -in plain.txt -out out.txt -pass pass:123456   //密码123456
      
      • RSA:

      RSA 的用法如下:
      
      openssl rsa [-inform PEM|NET|DER] [-outform PEM|NET|DER] [-in filename] [-passin arg] [-out filename] [-passout arg]
         [-sgckey] [-des] [-des3] [-idea] [-text] [-noout] [-modulus] [-check] [-pubin] [-pubout] [-engine id]
      常用选项:
      
      -in filename:指明私钥文件
      
      -out filename:指明将提取出的公钥保存至指定文件中 
      
      -pubout:根据私钥提取出公钥 
      
      • MD5:

      openssl passwd -1 -in test.txt -salt 12345678    
      
      生成密码需要使用的标准命令为 passwd ,用法如下:
      
      openssl passwd [-crypt] [-1] [-apr1] [-salt string] [-in file] [-stdin] [-noverify] [-quiet] [-table] {password}
      常用选项有:
      
      -1:使用md5加密算法
      
      -salt string:加入随机数,最多8位随机数
      
      -in file:对输入的文件内容进行加密
      
      -stdion:对标准输入的内容进行加密
      
    3. 在Ubuntu中实现对实验二中的“wc服务器”通过混合密码系统进行防护

    • 头文件:
    #include <openssl/ssl.h>
    #include <openssl/err.h>
    
    • SSL库初始化
    SSL_library_init();
    
    • 载入所有 SSL 算法
    OpenSSL_add_all_algorithms();
    
    • 载入所有 SSL 错误消息
    SSL_load_error_strings();
    
    • 产生一个 SSL_CTX
    ctx = SSL_CTX_new(SSLv23_server_method());
    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);
        }
    
    
    • 基于 ctx 产生一个新的 SSL,并将连接用户的 socket 加入到 SSL
    ssl = SSL_new(ctx);
    SSL_set_fd(ssl, new_server_socket_fd);
    
    • 建立 SSL 连接
    if (SSL_accept(ssl) == -1) {
        perror("accept");
        close(new_fd);
        break;
        }
    
    • SSL数据传输
    int len = SSL_read(ssl, buffer, MAXBUF);
        
    if (len > 0)
        printf("接收消息成功:'%s',共%d个字节的数据
    ", buffer, len);
    else
        printf("消息接收失败!错误代码是%d,错误信息是'%s'
    ",errno, strerror(errno));
        
    
    • 客户端与服务器传输完数据后,关闭 SSL 连接,释放 SSL
    SSL_shutdown(ssl);
    
    SSL_free(ssl);
    
    • 释放 CTX
    SSL_CTX_free(ctx);
    

    代码已上传至码云

    
    #include<netinet/in.h> // sockaddr_in
    ……
    #include <openssl/ssl.h>
    #include <openssl/err.h>
    ……
    #include<string.h> // bzero
    
    #define SERVER_PORT 8000
    #define LENGTH_OF_LISTEN_QUEUE 20
    #define BUFFER_SIZE 1024
    #define FILE_NAME_MAX_SIZE 512
    #define MAX 10000000
    #define MAXBUF 1024
    
    int main(void)
    {
    // 声明并初始化一个服务器端的socket地址结构
    struct sockaddr_in server_addr;
    ……
    server_addr.sin_port = htons(SERVER_PORT);
    SSL_CTX *ctx;    //ssl数据结构
    
    /* 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,若成功,返回socket描述符
    int server_socket_fd = socket(PF_INET, SOCK_STREAM, 0);
    ……
    
    // 绑定socket和socket地址结构
    ……
    
    // socket监听
    ……
    
    
    while(1)
        {
        SSL *ssl;
        
        
        // 定义客户端的socket地址结构
        struct sockaddr_in client_addr;
        socklen_t client_addr_length = sizeof(client_addr);
            
        // 接受连接请求,返回一个新的socket(描述符),这个新socket用于同连接的客户端通信
        // accept函数会把连接到的客户端信息写到client_addr中
        int new_server_socket_fd = accept(server_socket_fd, (struct sockaddr*)&client_addr, &client_addr_length);
        ……
            
        /* 基于 ctx 产生一个新的 SSL */
        ssl = SSL_new(ctx);
        /* 将连接用户的 socket 加入到 SSL */
        SSL_set_fd(ssl, new_server_socket_fd);
        
        /* 建立 SSL 连接 */
        if (SSL_accept(ssl) == -1) {
            perror("accept");
            close(new_fd);
            break;
            }
        
        
        // recv函数接收数据到缓冲区buffer中
        char buffer[BUFFER_SIZE];
        bzero(buffer, BUFFER_SIZE);
        if(recv(new_server_socket_fd, buffer, BUFFER_SIZE, 0) < 0)
            {
                perror("Server Recieve Data Failed:");
                break;
                }
        // 然后从buffer(缓冲区)拷贝到file_name中
        
        int len = SSL_read(ssl, buffer, MAXBUF);
        
        if (len > 0)
            printf("接收消息成功:'%s',共%d个字节的数据
    ", buffer, len);
        else
            printf("消息接收失败!错误代码是%d,错误信息是'%s'
    ",errno, strerror(errno));
        
        
        char file_name[FILE_NAME_MAX_SIZE+1];
        ……
        
        
        
        // 打开文件并读取文件数据
        FILE *fp = fopen(file_name, "r");
        if(NULL == fp)
            {
                printf("File:%s Not Found
    ", file_name);
            }
        else
            {
                //printf("buffer:%s
    ",buffer);//buffer为filename
                    
                char *argv[]={"wc","-w",file_name,0};
                execvp( "wc" ,argv);
                    
                fclose(fp);
                
                /* 关闭 SSL 连接 */
                SSL_shutdown(ssl);
                
                /* 释放 SSL */
                SSL_free(ssl);
                
                
                
            }
        // 关闭与客户端的连接
        close(new_server_socket_fd);
        }
    // 关闭监听用的socket
    close(server_socket_fd);
    
     /* 释放 CTX */
    SSL_CTX_free(ctx);
    
    return 0;
    }
    
    


    三、实验过程中遇到的问题和解决方案

    • 问题1:安装OpenSSL环境的时候,一切按照步骤来,在编写测试文件的时候还是出现了无法识别头文件的错误,我没截图,终端提示error:cannnot found #include <openssl/evp.h>的错误
    • 问题1解决方案:各种百度,在知乎里找到一个回答:Mac10.10 brew安装PHP提示Cannot find OpenSSL's <evp.h>
      里面提示安装Xcode命令行
    xcode-select --install
    

    然后居然就可以了,也不会再报错,可以运行测试代码

    四、实验体会与总结

    本次实验在MAC OS系统下也可以完成,需要特别注意的是静态库动态库的链接,以及头文件的使用,对于OpenSSL的使用我们还不是很熟悉,很多步骤都是一边网上查资料一边百度一边尝试着写的,这也耗费了一些时间,不过网上对于OpenSSL的研究很多,能参考的资料就更丰富了,花时间学习就会有很多收获。

    五、参考资料

  • 相关阅读:
    二测试组织
    如何编写测试计划
    C#三种字符串拼接方法的效率对比
    CSS内容溢出时,显示省略号
    JQuery文件上传控件Uploadify文档
    LINQ to Entities 不识别方法“Boolean Like(System.String, System.String)”,因此该方法无法转换为存储表达式。
    Linux 各目录的作用
    服务器注释事项
    资料:mnist.pkl.gz数据包的下载以及数据内容解释
    RockPaperScissorsLizardSpock Python实现
  • 原文地址:https://www.cnblogs.com/zhuohua/p/8030486.html
Copyright © 2020-2023  润新知