精选文章

Android下使用TCPDUMP抓包Wireshark分析数据 如果想分析Android下某个APP的网络数据交互,需要在Android手机上抓包,最常用的抓包工具非tcpdump莫属,用tcpdump生成Wireshark识别的pcap文件,然后将pcap文件下载到电脑上,用电脑上的Wireshark加载pcap文件,通过Wireshark分析tcpdump抓取的数据。...

继续阅读

Mac下部署Android开发环境附加NDK 作为开发者,我们深有体会,不管是进行什么开发,为了部署开发环境,我们往往需要折腾很长时间、查阅很多资料才能完成,而且这次折腾完了,下次到了另一台新电脑上又得重新来过,整个部署过程记得还好,要是不记得又得重新开始,而且遇到Android这种GFW阻隔了开发资源下载链接的环境部署,又尤其浪费时间。所以这也是我写下这篇教程的初衷跟动力源泉,希望大家参考了这篇教程以后可以轻轻松松在Mac系统下将Android环境部署好。...

继续阅读

稍顯嚴肅的台中 坦白說,留在腦海中的台中影像並不多,來台灣之前在Booking上只訂到了台中的一家青旅,第一次住青旅有些不習慣,幹什麼都放不開。 同屋的一個男生是台灣人,不過一年中四分之三的時間在上海跟北京,這麼說來跟我還是比較有共同話題的。得之我準備花15天的時間環島,覺得太倉促了,他們大學時期花一個半月的時間也不見得能將台灣島給逛完。我只能無奈地表示,兩岸允許的簽證時間有限,自己的空閒時間更有限,只能用打卡式的旅行了,我深知正真地旅行應該慢下來,融入當地的環境,感受他們的風土人情,但第一次只能這樣作罷,以後換成民進黨上台,形勢會變成怎樣還不得而知,能否再過來還是個未知數。而我一向信奉的人生格言是秉燭夜遊,活在當下,所以,理解自己吧。...

继续阅读

為之留戀的新竹 來新竹之前本沒有對她有過高的期待,慢慢對她加分要從桃園火車站出發前往新竹開始。 在桃園火車站的候車月台上,有醒目的旅遊資料發放處,這上面的擺放的全是新竹的旅遊宣傳資料,關鍵的是資料做得非常簡潔易懂,而接下來一天的新竹之行就全部是依據這份寶典的指引來完成的。...

继续阅读

從桃園開始台灣之行 初到台灣恰逢華夏銀行系統升級,特意準備的華夏銀聯卡在桃園機場沒能派上用場,只好用建行在機場5000塊,算下來是很不划算的,但是沒辦法,誰叫我出機場就得花錢呢。 從機場打車到桃園的酒店,花了將近六百塊新台幣,到酒店時五點多,天已經漸亮了,洗漱完等到七點吃過早餐就開始補覺囉,一覺醒來已是中午,帶著換下來的衣服外出找自助洗衣店,順便覓食。...

继续阅读

  • Prev
  • Next

SSL通信流程函数封装

文章分类 : C语言, 应用与编程, 网络

OpenSSL的API使用起来与我们常用的普通网络通信函数大同小异,主要分为初始化阶段、密钥载入及验证阶段、创建SSL(类似于文件描述符(套结字)创建函数socket)阶段、绑定套结字阶段(类似于bind函数)、请求建立连接阶段(客户端特有,类似于connect)、接受连接请求阶段(服务端特有,类似于accept函数)、数据收发阶段(类似于read和write)、结束连接阶段以及结束监听阶段(类似于close)。为了让SSL通信过程更加清晰明了,故自己用C语言封装了5个主要函数,让SSL通信流程为开发者快速掌握、一目了然。

SSL通信流程函数封装:

1、SSL初始化:

int ssl_init(SSL_CTX *ctx)
{
    /* 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(stderr);
        return -1;
    }
}

2、密钥载入及验证:

int ssl_load(SSL_CTX *ctx, char *certificate, char *privateKey)
{
    if (NULL == ctx || NULL == certificate || NULL == privateKey) return -1;
    /* 载入用户的数字证书, 此证书用来发送给客户端。 证书里包含有公钥 */
    if (SSL_CTX_use_certificate_file(ctx,certificate, SSL_FILETYPE_PEM) <= 0)
    {
        ERR_print_errors_fp(stderr);
        return -1;
    }
    /* 载入用户私钥 */
    if (SSL_CTX_use_PrivateKey_file(ctx, privateKey, SSL_FILETYPE_PEM) <= 0)
    {
        ERR_print_errors_fp(stderr);
        return -1;
    }
    /* 检查用户私钥是否正确 */
    if (!SSL_CTX_check_private_key(ctx))
    {
        ERR_print_errors_fp(stderr);
        return -1;
    }
}

3、服务端创建SSL对象并绑定套结字,接受指定端口(或指定地址)的连接请求:

int ssl_accept(SSL_CTX *ctx, int *sockfd, SSL **ssl, char *port, char *addr)
{
    struct sockaddr_in my_addr, their_addr;
    int new_fd, len = sizeof(struct sockaddr);
    if (NULL == ctx || NULL == socked || NULL == ssl || NULL == port) return -1;
    /* 开启一个 socket 监听 */
    if ((*sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("socket");
        return -1;
    }
    bzero(&my_addr, sizeof(my_addr));
    my_addr.sin_family = PF_INET;
    my_addr.sin_port = htons(port);
    if (addr)
        my_addr.sin_addr.s_addr = inet_addr(addr);
    else
        my_addr.sin_addr.s_addr = INADDR_ANY;
    if (bind(*sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr)) < 0)
    {
        perror("bind");
        return -1;
    }
    if (listen(*sockfd, 3) < 0)
    {
        perror("listen");
        return -1;
    }
    /* 等待客户端连上来 */
    bzero(&their_addr, sizeof(their_addrr));
    if ((new_fd = accept(sockfd, (struct sockaddr *) &their_addr, &len)) < 0)
    {
        perror("accept");
        return -1;
    }
    else
        printf("server: got connection from %s, port %d,
                socket %d\n",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) < 0)
    {
        perror("accept");
        close(new_fd);
        return -1;
    }
    return new_fd;
}

4、客户端创建SSL对象并绑定套结字,向指定端口、地址发起连接请求:

int ssl_connect(SSL_CTX *ctx, int *sockfd, SSL **ssl, char *port, char *addr)
{
    struct sockaddr_in dest;
    if (NULL == ctx || NULL == sockfd ||
        NULL == ssl || NULL == port || NULL == addr)
        return -1;
    /* 创建一个 socket 用于 tcp 通信 */
    if ((*sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("Socket");
        return -1;
    }
    /* 初始化服务器端(对方)的地址和端口信息 */
    bzero(&dest, sizeof(dest));
    dest.sin_family = AF_INET;
    dest.sin_port = htons(atoi(port));
    if (inet_aton(addr, (struct in_addr *) &dest.sin_addr.s_addr) == 0)
    {
        perror(addr);
        return -1;
    }
    /* 连接服务器 */
    if (connect(*sockfd, (struct sockaddr *) &dest, sizeof(dest)) < 0)
    {
        perror("Connect ");
        return -1;
    }
    /* 基于 ctx 产生一个新的 SSL */
    *ssl = SSL_new(ctx);
    SSL_set_fd(*ssl, *sockfd);
    /* 建立 SSL 连接 */
    if (SSL_connect(*ssl) < 0)
    {
        ERR_print_errors_fp(stderr);
        return -1;
    }
    return 0;
}

5、数据收发阶段采用SSL_read、SSL_write函数,用法跟read、write一样,用SSL对象指针代替文件描述符(套结字)即可。

6、结束连接阶段以及结束监听阶段:

int ssl_close(SSL_CTX *ctx, SSL *ssl, int sockfd, int new_fd)
{
    if (NULL == ctx || NULL == ssl || sockfd < 0 || new_fd < 0) return -1;
    /* 关闭 SSL 连接 */
    SSL_shutdown(ssl);
    /* 释放 SSL */
    SSL_free(ssl);
    /* 关闭 socket(服务端专用) */
    if (new_fd)
        close(new_fd);
    /* 关闭监听的 socket */
    close(sockfd);
    /* 释放 CTX */
    SSL_CTX_free(ctx);
    return 0;
}

 

除非注明,文章均为CppLive 编程在线原创,转载请注明出处,谢谢。

本文地址:https://www.cpplive.com/html/1394.html

这里因为你的留言而存在!!!

You must be logged in to post a comment.