[国嵌攻略][180][加密传输优化]

OpenSSL编程模型

客户端模型

1.初始化

2.创建SSL

3.数据收发

4.关闭

编译程序

gcc -lssl client.c -o client   编译PC版

arm-linux-gcc -L .../_install/lib/ -lssl -lcrypto -I .../_install/include/ client.c -o client   编译ARM版

服务器模型

1.初始化

2.载入数字证书和私钥

3.创建SSL

4.数据收发

5.关闭

编译程序

gcc -lssl server.c -o server

测试程序

当客户端连接到服务器时,服务器会把对应的数字证书发送给客户端,在以后的通讯过程中就用发送的数据证书和服务器的私钥进行加密和解密。

创建私钥

openssl genrsa -out privkey.pem 2048   genrsa表示创建私钥,-out privkey.pem输出私钥文件名,2048表示位数

创建数字证书

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

client.c

/********************************************************************
*名称:client.c
*作者:D
*时间:2016.04.03
*功能:网络安全传输系统客户端
*********************************************************************/

/********************************************************************
*头文件
*********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include <openssl/ssl.h>
#include <openssl/err.h>

/********************************************************************
*宏定义
*********************************************************************/
#define SERVER_PORT 3333   //网络端口

/********************************************************************
*函数原型
*********************************************************************/
int main(int argc, char **argv);
void menu(SSL *ssl);
void upload(SSL *ssl);
void download(SSL *ssl);
void quit(SSL *ssl);

/********************************************************************
*名称:main
*参数:
*    argc   参数数量
*    argv   参数列表
*返回:
*    stat    0 成功
*           -1 失败
*功能:主函数
*********************************************************************/
int main(int argc, char **argv){
    //参数检查
    if(argc != 2){
        printf("Usage:
	./client <ip address>
");
        return -1;
    }
    
    //创建 SSL
    SSL_CTX *ctx;
    
    SSL_library_init();
    OpenSSL_add_all_algorithms();
    SSL_load_error_strings();
    
    ctx = SSL_CTX_new(SSLv23_client_method());   //客户端模式
    
    //创建标识
    int clientfd;
    
    clientfd = socket(AF_INET, SOCK_STREAM, 0);
    if(clientfd == -1){
        printf("Can not create socket!
");
        return -1;
    }
    
    //建立连接
    struct sockaddr_in serverAddr;
    int isConnect;
    
    serverAddr.sin_family = AF_INET;                   //设置协议
    serverAddr.sin_port = htons(SERVER_PORT);          //设置端口
    serverAddr.sin_addr.s_addr = inet_addr(argv[1]);   //设置地址
    bzero(serverAddr.sin_zero, 8);                     //设置为零
    
    isConnect = connect(clientfd, (struct sockaddr *)&serverAddr, sizeof(struct sockaddr));
    if(isConnect == -1){
        printf("Can not connect to server!
");
        return -1;
    }
    
    //连接 SSL
    SSL *ssl;
    
    ssl = SSL_new(ctx);
    SSL_set_fd(ssl, clientfd);
    SSL_connect(ssl);

    //显示菜单
    menu(ssl);
    
    //关闭 SSL
    SSL_shutdown(ssl);
    SSL_free(ssl);
    
    //关闭连接
    close(clientfd);
    
    //释放 SSL
    SSL_CTX_free(ctx);
    
    return 0;
}

/********************************************************************
*名称:menu
*参数:
*    ssl   客户端标志
*返回:
*    none
*功能:显示菜单
*********************************************************************/
void menu(SSL *ssl){
    //显示菜单
    while(1){
        //打印菜单
        printf("
");
        printf("**********************************************************************
");
        printf("*                               Client                               *
");
        printf("*[1]Upload Files                                                     *
");
        printf("*[2]Download Files                                                   *
");
        printf("*[3]Exit                                                             *
");
        printf("**********************************************************************
");
        printf("Please Select: ");
        
        //输入命令
        int num;
        
        scanf("%d", &num);
        
        //处理命令
        switch(num){
            //上传文件
            case 1:
                upload(ssl);
                break;
            
            //下载文件
            case 2:
                download(ssl);
                break;
            
            //退出程序
            case 3:
                quit(ssl);
                break;
                
            //错误命令
            default:
                printf("
Please input again!
");
                break;
        }
        
        //是否退出
        if(num == 3){
            break;
        }
    }
}

/********************************************************************
*名称:upload
*参数:
*    ssl   客户端标志
*返回:
*    none
*功能:上传文件
*********************************************************************/
void upload(SSL *ssl){
    //输入文件名称
    char filename[20];
    
    printf("
Upload file: ");
    scanf("%s", &filename);
    
    //打开上传文件
    int fd;
    
    fd = open(filename, O_RDONLY);
    if(fd == -1){
        printf("Can not open file!
");
        return ;
    }
    
    //发送上传命令
    char cmd = 'U';
    
    SSL_write(ssl, (void *)&cmd, sizeof(cmd));
    
    //发送文件名称
    int namesize;
    
    namesize = strlen(filename) + 1;   //加上字符串接收符
    
    SSL_write(ssl, (void *)&namesize, sizeof(namesize));
    SSL_write(ssl, (void *)&filename, namesize);
    
    //发送文件长度
    struct stat fstat;
    int isState;
    
    isState = stat(filename, &fstat);
    if(isState == -1){
        printf("Can not get file state!
");
        return ;
    }
    
    SSL_write(ssl, (void *)&(fstat.st_size), sizeof(fstat.st_size));
    
    //发送文件内容
    char buf[1024];
    int  num;
    
    num = read(fd, (void *)buf, sizeof(buf));
    while(num > 0){
        //发送文件内容
        SSL_write(ssl, (void *)&buf, num);
        
        //读取文件内容
        num = read(fd, (void *)buf, sizeof(buf));
    }
    
    //关闭上传文件
    close(fd);
}

/********************************************************************
*名称:download
*参数:
*    ssl   客户端标志
*返回:
*    none
*功能:下载文件
*********************************************************************/
void download(SSL *ssl){
    //输入文件名称
    char filename[20];
    
    printf("
Download file: ");
    scanf("%s", &filename);
    
    //创建下载文件
    int fd;
    
    fd = open(filename, O_RDWR | O_CREAT, 0777);
    if(fd == -1){
        printf("Can not create file!
");
        return ;
    }
    
    //发送下载命令
    char cmd = 'D';
    
    SSL_write(ssl, (void *)&cmd, sizeof(cmd));
    
    //发送文件名称
    int namesize;
    
    namesize = strlen(filename) + 1;   //加上字符串接收符
    
    SSL_write(ssl, (void *)&namesize, sizeof(namesize));
    SSL_write(ssl, (void *)&filename, namesize);
    
    //接收文件长度
    int fileszie;
    
    SSL_read(ssl, &fileszie, sizeof(fileszie));
    
    //接收文件内容
    char buf[1024];
    int  num;
    
    num = SSL_read(ssl, (void *)buf, sizeof(buf));
    while(num > 0){
        //写入接收内容
        write(fd, (void *)&buf, num);
        
        //是否接收结束
        fileszie = fileszie - num;
        if(fileszie == 0){
            break;
        }
        
        //接收文件内容
        num = SSL_read(ssl, (void *)buf, sizeof(buf));
    }
    
    //关闭下载文件
    close(fd);
}

/********************************************************************
*名称:quit
*参数:
*    ssl   客户端标志
*返回:
*    none
*功能:退出程序
*********************************************************************/
void quit(SSL *ssl){
    //发送退出命令
    char cmd = 'Q';
    
    SSL_write(ssl, (void *)&cmd, sizeof(cmd));
    
    //清除屏幕显示
    system("clear");
}

server.c

/********************************************************************
*名称:server.c
*作者:D
*时间:2016.04.05
*功能:网络安全传输系统服务端
*********************************************************************/

/********************************************************************
*头文件
*********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>

#include <openssl/ssl.h>
#include <openssl/err.h>

/********************************************************************
*宏定义
*********************************************************************/
#define SERVER_PORT 3333  //网络端口

/********************************************************************
*函数原型
*********************************************************************/
int main(int argc, char **argv);
void menu(SSL *ssl);
void upload(SSL *ssl);
void download(SSL *ssl);

/********************************************************************
*名称:main
*参数:
*    argc   参数数量
*    argv   参数列表
*返回:
*    stat    0 成功
*           -1 失败
*功能:主函数
*********************************************************************/
int main(int argc, char **argv){
    //创建 SSL
    SSL_CTX *ctx;
    
    SSL_library_init();
    OpenSSL_add_all_algorithms();
    SSL_load_error_strings();
    
    ctx = SSL_CTX_new(SSLv23_server_method());   //服务器模式
    
    //配置 SSL
    int isCert, isPriv;
    
    isCert = SSL_CTX_use_certificate_file(ctx, "./certkey.pem", SSL_FILETYPE_PEM);   //载入数字证书
    if(isCert == -1){
        ERR_print_errors_fp(stdout);
        return -1;
    }
    
    isPriv = SSL_CTX_use_PrivateKey_file(ctx, "./privkey.pem", SSL_FILETYPE_PEM);    //载入用户私钥
    if(isPriv == -1){
        ERR_print_errors_fp(stdout);
        return -1;
    }
    
    //检测 SSL
    int isCheck;
    
    isCheck = SSL_CTX_check_private_key(ctx);
    if(isCheck == 0){
        ERR_print_errors_fp(stdout);
        return -1;
    }
    
    //创建标识
    int serverfd;
    
    serverfd = socket(AF_INET, SOCK_STREAM, 0);
    if(serverfd == -1){
        printf("Can not create socket!
");
        return -1;
    }
    
    //绑定地址
    struct sockaddr_in serverAddr;
    int isBand;
    
    serverAddr.sin_family = AF_INET;                   //设置协议
    serverAddr.sin_port = htons(SERVER_PORT);          //设置端口
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);    //设置地址
    bzero(serverAddr.sin_zero, 8);                     //设置为零
    
    isBand = bind(serverfd, (struct sockaddr *)&serverAddr, sizeof(struct sockaddr));
    if(isBand == -1){
        printf("Can not bind!
");
        return -1;
    }
    
    //监听端口
    int isListen;
    
    isListen = listen(serverfd, 5);
    if(isListen == -1){
        printf("Can not listen!
");
        return -1;
    }
    
    //处理连接
    while(1){
        //等待连接
        socklen_t clientAddrLen;
        struct sockaddr_in clientAddr;
        int clientfd;

        clientAddrLen = sizeof(struct sockaddr);
        clientfd = accept(serverfd, (struct sockaddr *)&clientAddr, &clientAddrLen);
        if(clientfd == -1){
            printf("Can not accept!
");
            return -1;
        }
        
        //连接 SSL
        SSL *ssl;
        int isAccept;
        
        ssl = SSL_new(ctx);
        SSL_set_fd(ssl, clientfd);
        
        isAccept = SSL_accept(ssl);
        if(isAccept == -1){
            ERR_print_errors_fp(stdout);
            return -1;
        }
        
        //处理菜单
        menu(ssl);
        
        //关闭 SSL
        SSL_shutdown(ssl);
        SSL_free(ssl);
        
        //关闭连接
        close(clientfd);
    }
    
    //关闭连接
    close(serverfd);
    
    //释放 SSL
    SSL_CTX_free(ctx);
}

/********************************************************************
*名称:menu
*参数:
*    ssl   客户端标志
*返回:
*    none
*功能:处理菜单
*********************************************************************/
void menu(SSL *ssl){
    //处理菜单
    while(1){
        //读取命令
        char cmd;
    
        SSL_read(ssl, (void *)&cmd, sizeof(cmd));
        
        //处理命令
        switch(cmd){
            //上传文件
            case 'U':
                upload(ssl);
                break;
            
            //下载文件
            case 'D':
                download(ssl);
                break;
                
            //退出程序
            case 'Q':
                break;
                
            //其他命令
            default:
                break;
        }
        
        //是否退出
        if(cmd == 'Q'){
            break;
        }
    }
}

/********************************************************************
*名称:upload
*参数:
*    ssl   客户端标志
*返回:
*    none
*功能:上传文件
*********************************************************************/
void upload(SSL *ssl){
    //接收文件名称
    int namesize;
    char filename[20];
    
    SSL_read(ssl, (void *)&namesize, sizeof(namesize));
    SSL_read(ssl, (void *)&filename, namesize);
    
    //创建上传文件
    int fd;
    
    fd = open(filename, O_RDWR | O_CREAT, 0777);
    if(fd == -1){
        printf("Can not create file!
");
        return ;
    }
    
    //接收文件长度
    int fileszie;
    
    SSL_read(ssl, &fileszie, sizeof(fileszie));
    
    //接收文件内容
    char buf[1024];
    int  num;
    
    num = SSL_read(ssl, (void *)buf, sizeof(buf));
    while(num > 0){
        //写入接收内容
        write(fd, (void *)&buf, num);
        
        //是否接收结束
        fileszie = fileszie - num;
        if(fileszie == 0){
            break;
        }
        
        //接收文件内容
        num = SSL_read(ssl, (void *)buf, sizeof(buf));
    }
    
    //关闭上传文件
    close(fd);
}

/********************************************************************
*名称:download
*参数:
*    ssl   客户端标志
*返回:
*    none
*功能:下载文件
*********************************************************************/
void download(SSL *ssl){
    //接收文件名称
    int namesize;
    char filename[20];
    
    SSL_read(ssl, (void *)&namesize, sizeof(namesize));
    SSL_read(ssl, (void *)&filename, namesize);
    
    //打开下载文件
    int fd;
    
    fd = open(filename, O_RDONLY);
    if(fd == -1){
        printf("Can not open file!
");
        return ;
    }
    
    //发送文件长度
    struct stat fstat;
    int isState;
    
    isState = stat(filename, &fstat);
    if(isState == -1){
        printf("Can not get file state!
");
        return ;
    }
    
    SSL_write(ssl, (void *)&(fstat.st_size), sizeof(fstat.st_size));
    
    //发送文件内容
    char buf[1024];
    int  num;
    
    num = read(fd, (void *)buf, sizeof(buf));
    while(num > 0){
        //发送文件内容
        SSL_write(ssl, (void *)&buf, num);
        
        //读取文件内容
        num = read(fd, (void *)buf, sizeof(buf));
    }
    
    //关闭下载文件
    close(fd);
}
原文地址:https://www.cnblogs.com/d442130165/p/5356702.html