zoukankan      html  css  js  c++  java
  • 2019-2020-1 20175304 20175303 20175327 20175335 实验五 通讯协议设计

    2019-2020-1 20175304 20175303 20175327 20175335 实验五 通讯协议设计

    一、实验内容

    通讯协议设计-1

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

    2.提交运行结果截图

    通讯协议设计-2

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

    2.提交测试截图

    通讯协议设计-3

    1 运行实验箱中,ARM调用Z32算法的实验,提交实验截图

    2 用Z32的国密算法重新改写“wc服务器”的混合密码系统防护,提交运行截图

    二、实验过程

    通讯协议设计-1

    1.OpenSSL简介

    OpenSSL是一个SSL协议的开源实现,采用C语言作为开发语言,具备了跨平台的能力,支持Unix/Linux、Windows、Mac OS等多种平台。

    2.OpenSSL整个软件包大概可以分成三个主要的功能部分:

    • 密码算法库
    • SSL协议库
    • 应用程序
    • OpenSSL源码的目录结构也是围绕这三个功能部分进行规划的。

    密码算法库是一个强大完整的密码算法库,它是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等)。

    1.在Mac下OpenSSL的安装和使用

    • 一般Mac下都默认有openssl了,不用下载安装,可以直接使用openssl

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

    • 编写测试代码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

    • 实现 echo $? 进行执行,结果打印了一个0

    作业

    两人一组
    基于 Socket 实现 TCP 通信,一人实现服务器,一人实现客户端
    研究 OpenSSL 算法,测试对称算法中的 AES ,非对称算法中的 RSA , Hash 算法中的 MD5
    选用合适的算法,基于混合密码系统实现对 TCP 通信进行机密性、完整性保护。
    学有余力者,对系统进行安全性分析和改进。

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

    • 编写服务器端代码
      server.c
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    #define BUFLEN 10
    
    int main(int argc, char **argv)
    {
        int sockfd, newfd;
        struct sockaddr_in s_addr, c_addr;
        char buf[BUFLEN];
        socklen_t len;
        unsigned int port, listnum;
        
        /*建立socket*/
        if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
            perror("socket");
            exit(errno);
        }else
            printf("socket create success!
    ");
        /*设置服务器端口*/    
        if(argv[2])
            port = atoi(argv[2]);
        else
            port = 4567;
        /*设置侦听队列长度*/
        if(argv[3])
            listnum = atoi(argv[3]);
        else
            listnum = 3;
        /*设置服务器ip*/
        bzero(&s_addr, sizeof(s_addr));
        s_addr.sin_family = AF_INET;
        s_addr.sin_port = htons(port);
        if(argv[1])
            s_addr.sin_addr.s_addr = inet_addr(argv[1]);
        else
            s_addr.sin_addr.s_addr = INADDR_ANY;
        /*把地址和端口帮定到套接字上*/
        if((bind(sockfd, (struct sockaddr*) &s_addr,sizeof(struct sockaddr))) == -1){
            perror("bind");
            exit(errno);
        }else
            printf("bind success!
    ");
        /*侦听本地端口*/
        if(listen(sockfd,listnum) == -1){
            perror("listen");
            exit(errno);    
        }else
            printf("the server is listening!
    ");
        while(1){
            printf("*****************聊天开始***************
    ");
            len = sizeof(struct sockaddr);
            if((newfd = accept(sockfd,(struct sockaddr*) &c_addr, &len)) == -1){
                perror("accept");        
                exit(errno);
            }else
                printf("正在与您聊天的客户端是:%s: %d
    ",inet_ntoa(c_addr.sin_addr),ntohs(c_addr.sin_port));
            while(1){
            _retry:
                /******发送消息*******/
                bzero(buf,BUFLEN);
                printf("请输入发送给对方的消息:");
                /*fgets函数:从流中读取BUFLEN-1个字符*/
                fgets(buf,BUFLEN,stdin);
                /*打印发送的消息*/
                //fputs(buf,stdout);
                if(!strncasecmp(buf,"quit",4)){
                    printf("server 请求终止聊天!
    ");
                    break;
                }
                /*如果输入的字符串只有"
    ",即回车,那么请重新输入*/
                if(!strncmp(buf,"
    ",1)){
                    printf("输入的字符只有回车,这个是不正确的!!!
    ");
                    goto _retry;
                }    
                /*如果buf中含有'
    ',那么要用strlen(buf)-1,去掉'
    '*/            
                if(strchr(buf,'
    '))
                    len = send(newfd,buf,strlen(buf)-1,0);
                /*如果buf中没有'
    ',则用buf的真正长度strlen(buf)*/    
                else
                    len = send(newfd,buf,strlen(buf),0);
                if(len > 0)
                    printf("消息发送成功,本次共发送的字节数是:%d
    ",len);            
                else{
                    printf("消息发送失败!
    ");
                    break;            
                }
                /******接收消息*******/
                bzero(buf,BUFLEN);
                len = recv(newfd,buf,BUFLEN,0);
                if(len > 0)
                    printf("客户端发来的信息是:%s,共有字节数是: %d
    ",buf,len);
                else{
                    if(len < 0 )
                        printf("接受消息失败!
    ");
                    else
                        printf("客户端退出了,聊天终止!
    ");
                    break;        
                }
            }
            /*关闭聊天的套接字*/
            close(newfd);
            /*是否退出服务器*/
            printf("服务器是否退出程序:y->是;n->否? ");
            bzero(buf, BUFLEN);
            fgets(buf,BUFLEN, stdin);
            if(!strncasecmp(buf,"y",1)){
                printf("server 退出!
    ");
                break;
            }
        }
        /*关闭服务器的套接字*/
        close(sockfd);
        return 0;
    }
    • 客户端代码
      client.c
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    #define BUFLEN 10
    
    int main(int argc, char **argv)
    {
        int sockfd;
        struct sockaddr_in s_addr;
        socklen_t len;
        unsigned int port;
        char buf[BUFLEN];    
        
        /*建立socket*/
        if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
            perror("socket");
            exit(errno);
        }else
            printf("socket create success!
    ");
    
        /*设置服务器端口*/    
        if(argv[2])
            port = atoi(argv[2]);
        else
            port = 4567;
        /*设置服务器ip*/
        bzero(&s_addr, sizeof(s_addr));
        s_addr.sin_family = AF_INET;
        s_addr.sin_port = htons(port);
        if (inet_aton(argv[1], (struct in_addr *)&s_addr.sin_addr.s_addr) == 0) {
            perror(argv[1]);
            exit(errno);
        }
        /*开始连接服务器*/    
        if(connect(sockfd,(struct sockaddr*)&s_addr,sizeof(struct sockaddr)) == -1){
            perror("connect");
            exit(errno);
        }else
            printf("conncet success!
    ");
        
        while(1){
            /******接收消息*******/
            bzero(buf,BUFLEN);
            len = recv(sockfd,buf,BUFLEN,0);
            if(len > 0)
                printf("服务器发来的消息是:%s,共有字节数是: %d
    ",buf,len);
            else{
                if(len < 0 )
                    printf("接受消息失败!
    ");
                else
                    printf("服务器退出了,聊天终止!
    ");
                break;    
            }
        _retry:    
            /******发送消息*******/    
            bzero(buf,BUFLEN);
            printf("请输入发送给对方的消息:");
            /*fgets函数:从流中读取BUFLEN-1个字符*/
            fgets(buf,BUFLEN,stdin);
            /*打印发送的消息*/
            //fputs(buf,stdout);
            if(!strncasecmp(buf,"quit",4)){
                printf("client 请求终止聊天!
    ");
                break;
            }
            /*如果输入的字符串只有"
    ",即回车,那么请重新输入*/
            if(!strncmp(buf,"
    ",1)){
                printf("输入的字符只有回车,这个是不正确的!!!
    ");
                goto _retry;
            }
            /*如果buf中含有'
    ',那么要用strlen(buf)-1,去掉'
    '*/    
            if(strchr(buf,'
    '))
                len = send(sockfd,buf,strlen(buf)-1,0);
            /*如果buf中没有'
    ',则用buf的真正长度strlen(buf)*/    
            else
                len = send(sockfd,buf,strlen(buf),0);
            if(len > 0)
                printf("消息发送成功,本次共发送的字节数是:%d
    ",len);            
            else{
                printf("消息发送失败!
    ");
                break;            
            }
        }
        /*关闭连接*/
        close(sockfd);
    
        return 0;
    }
    • 实验截图

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

    AES

    • 代码
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <openssl/aes.h>
    
    int main(int argc, char** argv) {
        AES_KEY aes;
        unsigned char key[AES_BLOCK_SIZE];        // AES_BLOCK_SIZE = 16
        unsigned char iv[AES_BLOCK_SIZE];        // init vector
        unsigned char* input_string;
        unsigned char* encrypt_string;
        unsigned char* decrypt_string;
        unsigned int len;        // encrypt length (in multiple of AES_BLOCK_SIZE)
        unsigned int i;
    
        // check usage
        if (argc != 2) {
            fprintf(stderr, "%s <plain text>
    ", argv[0]);
            exit(-1);
        }
    
        // set the encryption length
        len = 0;
        if ((strlen(argv[1]) + 1) % AES_BLOCK_SIZE == 0) {
            len = strlen(argv[1]) + 1;
        } else {
            len = ((strlen(argv[1]) + 1) / AES_BLOCK_SIZE + 1) * AES_BLOCK_SIZE;
        }
    
        // set the input string
        input_string = (unsigned char*)calloc(len, sizeof(unsigned char));
        if (input_string == NULL) {
            fprintf(stderr, "Unable to allocate memory for input_string
    ");
            exit(-1);
        }
        strncpy((char*)input_string, argv[1], strlen(argv[1]));
    
        // Generate AES 128-bit key
        for (i=0; i<16; ++i) {
            key[i] = 32 + i;
        }
    
        // Set encryption key
        for (i=0; i<AES_BLOCK_SIZE; ++i) {
            iv[i] = 0;
        }
        if (AES_set_encrypt_key(key, 128, &aes) < 0) {
            fprintf(stderr, "Unable to set encryption key in AES
    ");
            exit(-1);
        }
    
        // alloc encrypt_string
        encrypt_string = (unsigned char*)calloc(len, sizeof(unsigned char));    
        if (encrypt_string == NULL) {
            fprintf(stderr, "Unable to allocate memory for encrypt_string
    ");
            exit(-1);
        }
    
        // encrypt (iv will change)
        AES_cbc_encrypt(input_string, encrypt_string, len, &aes, iv, AES_ENCRYPT);
    
        // alloc decrypt_string
        decrypt_string = (unsigned char*)calloc(len, sizeof(unsigned char));
        if (decrypt_string == NULL) {
            fprintf(stderr, "Unable to allocate memory for decrypt_string
    ");
            exit(-1);
        }
    
        // Set decryption key
        for (i=0; i<AES_BLOCK_SIZE; ++i) {
            iv[i] = 0;
        }
        if (AES_set_decrypt_key(key, 128, &aes) < 0) {
            fprintf(stderr, "Unable to set decryption key in AES
    ");
            exit(-1);
        }
    
        // decrypt
        AES_cbc_encrypt(encrypt_string, decrypt_string, len, &aes, iv, 
                AES_DECRYPT);
    
        // print
        printf("input_string = %s
    ", input_string);
        printf("encrypted string = ");
        for (i=0; i<len; ++i) {
            printf("%x%x", (encrypt_string[i] >> 4) & 0xf, 
                    encrypt_string[i] & 0xf);    
        }
        printf("
    ");
        printf("decrypted string = %s
    ", decrypt_string);
    
        return 0;
    }
    • 运行使用 gcc AES.c -o AES -lssl -lcrypto 进行编译

    • 运行截图

    RSA

    • 代码
    #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="hello,i am 175327fkn";
        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){
        //if((p_rsa=PEM_read_RSAPublicKey(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;
    }
    • 使用openssl工具
    • 生成一个密钥:openssl genrsa -out test.key 1024 (-out接生成的文件名)
    • 提取出公钥:openssl rsa -in test.key -pubout -out test_pub.key (-in接输入文件,-out接生成公钥的文件名)
    • 在目录中创建一个hello的文本文件
    • (利用生成的公钥加密文件:openssl rsautl -encrypt -in hello -inkey test_pub.key -pubin -out hello.en (-in接要加密的文件,-inkey接密钥,-pubin表明是用纯公钥文件加密,-out接加密后的文件)

    • 解密文件:openssl rsautl -decrypt -in hello.en -inkey test.key -out hello.de (-in接被加密的文件,-inkey接私钥文件,-out接解密后的文件)

    • 实验截图

    MD5

    • 代码
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <openssl/md5.h>
    
    int main(int argc, char** argv) {
       MD5_CTX hash_ctx;
       char input_string[128];
       unsigned char hash_ret[16];
       int i;
    
       // check usage
       if (argc != 2) {
           fprintf(stderr, "%s <input string>
    ", argv[0]);
           exit(-1);
       }
    
       // set the input string
       snprintf(input_string, sizeof(input_string), "%s
    ", argv[1]);
    
       // initialize a hash context 
       MD5_Init(&hash_ctx);
    
       // update the input string to the hash context (you can update
       // more string to the hash context)
       MD5_Update(&hash_ctx, input_string, strlen(input_string));
    
       // compute the hash result
       MD5_Final(hash_ret, &hash_ctx);
    
       // print
       printf("Input string: %s", input_string);
       printf("Output string: ");
       for (i=0; i<32; ++i) {
           if (i % 2 == 0) {
               printf("%x", (hash_ret[i/2] >> 4) & 0xf);
           } else {
               printf("%x", (hash_ret[i/2]) & 0xf);
           }
       }
       printf("
    ");
    
       return 0;
    }
    • 运行截图

    通讯协议设计-2

    1.了解混合密码系统

    • 混合密码系统:将对称密码和公钥密码的优势相结合的方法。一般情况下,将两种不同的方式相结合的做法就称为混合。

    • 将消息通过对称密码来加密,将加密消息时使用的密钥通过公钥密码来加密,这样的两步密码机制就是混合密码系统的本质。

    2.详细步骤

    • 生成私钥和证书:
    • openssl genrsa -out privkey.pem 1024

    • openssl req -new -x509 -key privkey.pem -out CAcert.pem -days 1095

    1.编译
    gcc server.c -o server -lssl -lcrypto
    gcc client.c -o client -lssl -lcrypto
    2.代码
    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 = 7838;
    
        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, "server->client");
            /* 发消息给客户端 */
            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;
    }

    client.c

    #include <stdio.h>  
    #include <string.h>  
    #include <errno.h>  
    #include <sys/socket.h>  
    #include <resolv.h>  
    #include <stdlib.h>  
    #include <netinet/in.h>  
    #include <arpa/inet.h>  
    #include <unistd.h>  
    #include <openssl/ssl.h>  
    #include <openssl/err.h>
     #include <openssl/evp.h>
      
      
    #define MAXBUF 1024  
      
    void ShowCerts(SSL * ssl)  
    {  
        X509 *cert;  
        char *line;  
      
        cert = SSL_get_peer_certificate(ssl);  
        if (cert != NULL) {  
            printf("数字证书信息:
    ");  
            line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);  
            printf("证书: %s
    ", line);  
            free(line);  
            line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);  
            printf("颁发者: %s
    ", line);  
            free(line);  
           X509_free(cert);  
        } else  
            printf("无证书信息!
    ");  
    }  
      
    int main(int argc, char **argv)  
    {  
        int sockfd, len;  
        struct sockaddr_in dest;  
        char buffer[MAXBUF + 1];  
        SSL_CTX *ctx;  
        SSL *ssl;  
      
        if (argc != 3) {  
            printf("参数格式错误!正确用法如下:
    		%s IP地址 端口
    	比如:	%s 127.0.0.1 80
    此程序用来从某个"  
                 "IP 地址的服务器某个端口接收最多 MAXBUF 个字节的消息",  
                 argv[0], argv[0]);  
            exit(0);  
        }  
      
        /* SSL 库初始化,参看 ssl-server.c 代码 */  
        SSL_library_init();  
        OpenSSL_add_all_algorithms();  
        SSL_load_error_strings();  
        ctx = SSL_CTX_new(SSLv23_client_method());  
        if (ctx == NULL) {  
            ERR_print_errors_fp(stdout);  
            exit(1);  
        }  
      
        /* 创建一个 socket 用于 tcp 通信 */  
        if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {  
            perror("Socket");  
            exit(errno);  
        }  
        printf("socket created
    ");  
      
        /* 初始化服务器端(对方)的地址和端口信息 */  
        bzero(&dest, sizeof(dest));  
        dest.sin_family = AF_INET;  
        dest.sin_port = htons(atoi(argv[2]));  
        if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0) {  
            perror(argv[1]);  
            exit(errno);  
        }  
        printf("address created
    ");  
      
        /* 连接服务器 */  
        if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0) {  
            perror("Connect ");  
            exit(errno);  
        }  
        printf("server connected
    ");  
      
        /* 基于 ctx 产生一个新的 SSL */  
        ssl = SSL_new(ctx);  
        SSL_set_fd(ssl, sockfd);  
        /* 建立 SSL 连接 */  
        if (SSL_connect(ssl) == -1)  
            ERR_print_errors_fp(stderr);  
        else {  
            printf("Connected with %s encryption
    ", SSL_get_cipher(ssl));  
            ShowCerts(ssl);  
        }  
      
        /* 接收对方发过来的消息,最多接收 MAXBUF 个字节 */  
        bzero(buffer, MAXBUF + 1);  
        /* 接收服务器来的消息 */  
        len = SSL_read(ssl, buffer, MAXBUF);  
        if (len > 0)  
            printf("接收消息成功:'%s',共%d个字节的数据
    ",  
                   buffer, len);  
        else {  
            printf  
                ("消息接收失败!错误代码是%d,错误信息是'%s'
    ",  
                 errno, strerror(errno));  
            goto finish;  
        }  
        bzero(buffer, MAXBUF + 1);  
        strcpy(buffer, "from client->server");  
        /* 发消息给服务器 */  
        len = SSL_write(ssl, buffer, strlen(buffer));  
        if (len < 0)  
            printf  
                ("消息'%s'发送失败!错误代码是%d,错误信息是'%s'
    ",  
                 buffer, errno, strerror(errno));  
        else  
            printf("消息'%s'发送成功,共发送了%d个字节!
    ",  
                   buffer, len);  
      
      finish:  
        /* 关闭连接 */  
        SSL_shutdown(ssl);  
        SSL_free(ssl);  
        close(sockfd);  
        SSL_CTX_free(ctx);  
        return 0;  
    }

    3.运行截图

    通讯协议设计-3(未完成)

    三、实验感想与体会

    这次的实验让我对于Openssl有了更深入的认识,学会了更多的东西,另外,也觉得通过OpenSSL来测试对称算法中的AES,非对称算法中的RSA,Hash算法中的MD5等,再一次深深的感受到了openssl对于密码学的方便。

    https://www.cnblogs.com/hollfull/p/11972839.html

  • 相关阅读:
    Head first javascript(七)
    Python Fundamental for Django
    Head first javascript(六)
    Head first javascript(五)
    Head first javascript(四)
    Head first javascript(三)
    Head first javascript(二)
    Head first javascript(一)
    Sicily 1090. Highways 解题报告
    Python GUI programming(tkinter)
  • 原文地址:https://www.cnblogs.com/DLuob/p/12008626.html
Copyright © 2011-2022 走看看