OpenSSL
openSSL 不僅僅是 SSL。它可以實現訊息摘要、檔案的加密和解密、數位憑證、數位簽章和隨機數字。關於 OpenSSL 庫的內容非常多,遠不是一篇文章可以容納的。
OpenSSL 不只是 API,它還是一個命令列工具。命令列工具可以完成與 API 同樣的工作,而且更進一步,可以測試 SSL 伺服器和客戶機。
伺服器編寫步驟源碼:建立win32空項目SSL_Server
//SSL_Server.cpp#include <iostream>#include <winsock2.h>#include <openssl/rsa.h> /* SSLeay stuff */#include <openssl/crypto.h>#include <openssl/x509.h>#include <openssl/pem.h>#include <openssl/ssl.h>#include <openssl/err.h>// #privatekey.pem// cmd: ..\openssl-1.0.1e\bin> openssl genrsa -out privatekey.pem 2048 --產生的是空密碼// #cacert.pem// cmd: ..\openssl-1.0.1e\bin> openssl req -new -x509 -key privatekey.pem -out cacert.pem -days 1095 -config ..\ssl\openssl.cnf #define CACERT "E:\\ReferData\\OpenSSL\\openssl-1.0.1e\\bin\\cacert.pem" #define PRIKEY "E:\\ReferData\\OpenSSL\\openssl-1.0.1e\\bin\\privatekey.pem" #define PRIKEY_CODE "women123" //----要與產生密鑰一致#define MAXBUF 1024#define DEFPORT 7838#pragma comment( lib, "ws2_32.lib" )#pragma comment( lib, "libeay32.lib" )#pragma comment( lib, "ssleay32.lib" )/************關於本文檔*********************************************filename: ssl-server.c*purpose: 示範利用 OpenSSL 庫進行基於 IP層的 SSL 加密通訊的方法,這是伺服器端例子*wrote by: zhoulifa(zhoulifa@163.com) 周立發(http://zhoulifa.bokee.com)Linux愛好者 Linux知識傳播者 SOHO族 開發人員 最擅長C語言*date time:2007-02-02 19:40*Note: 任何人可以任意複製代碼並運用這些文檔,當然包括你的商業用途* 但請遵循GPL*Thanks to:Google*Hope:希望越來越多的人貢獻自己的力量,為科學技術發展出力* 科技站在巨人的肩膀上進步更快!感謝有開源前輩的貢獻!*********************************************************************/int main(){ int sockfd, new_fd; int len; struct sockaddr_in my_addr, their_addr; char buf[MAXBUF + 1]; SSL_CTX *ctx; SSL_library_init();/* SSL 庫初始化 */ OpenSSL_add_all_algorithms(); /* 載入所有 SSL 演算法 */ SSL_load_error_strings();/* 載入所有 SSL 錯誤訊息 */ ctx = SSL_CTX_new(SSLv23_server_method()); /* 以 SSL V2 和 V3 標準相容方式產生一個 SSL_CTX ,即 SSL Content Text *//* 也可以用 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, CACERT, SSL_FILETYPE_PEM) <= 0) /* 載入使用者的數位憑證, 此認證用來發送給用戶端。 認證裡包含有公開金鑰 */{ ERR_print_errors_fp(stdout); exit(1); } //SSL_CTX_set_default_passwd_cb_userdata(ctx,PRIKEY_CODE); //若不是使用的空私密檔案,且沒有這一行代碼,則會出現“EnterPEM pess phrass:”---輸入密碼 if (SSL_CTX_use_PrivateKey_file(ctx, PRIKEY, 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); }WSADATA wsaData; int ret = WSAStartup( MAKEWORD(2, 2), &wsaData );if ( ret != 0 ){std::cout<<"WSAStartup error."<<std::endl;return -1;} /* 開啟一個 socket 監聽 */ if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(1); } else printf("socket created\n");memset (&my_addr, 0, sizeof(my_addr)); my_addr.sin_family = PF_INET; my_addr.sin_port = htons(DEFPORT); 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\n"); if (listen(sockfd, 2) == -1) { perror("listen"); exit(1); } else printf("begin listen\n"); 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\n",inet_ntoa(their_addr.sin_addr),ntohs(their_addr.sin_port), new_fd); ssl = SSL_new(ctx);/* 基於 ctx 產生一個新的 SSL */ SSL_set_fd(ssl, new_fd);/* 將串連使用者的 socket 加入到 SSL */ if (SSL_accept(ssl) == -1) /* 建立 SSL 串連 */{ perror("accept"); closesocket(new_fd); break; } /* 開始處理每個新串連上的資料收發 */ memset(buf, 0,MAXBUF + 1); strcpy(buf, "server->client"); /* 發訊息給用戶端 */ len = SSL_write(ssl, buf, strlen(buf)); if (len <= 0) { printf("訊息'%s'發送失敗!錯誤碼是%d,錯誤資訊是'%s'\n",buf, errno, strerror(errno)); goto finish; } else printf("訊息'%s'發送成功,共發送了%d個位元組!\n",buf, len); memset(buf,0, MAXBUF + 1); /* 接收用戶端的訊息 */ len = SSL_read(ssl, buf, MAXBUF); if (len > 0) printf("接收訊息成功:'%s',共%d個位元組的資料\n",buf, len); else printf("訊息接收失敗!錯誤碼是%d,錯誤資訊是'%s'\n",errno, strerror(errno)); finish: /* 處理每個新串連上的資料收髮結束 */ SSL_shutdown(ssl);/* 關閉 SSL 串連 */ SSL_free(ssl); /* 釋放 SSL */ closesocket(new_fd); /* 關閉 socket */ } closesocket(sockfd); /* 關閉監聽的 socket */ SSL_CTX_free(ctx);/* 釋放 CTX */ return 0;}用戶端編寫步驟源碼:建立win32空項目SSL_Client
//SSL_Client.cpp#include <iostream> #include <winsock2.h>#include <openssl/rsa.h> /* SSLeay stuff */#include <openssl/crypto.h>#include <openssl/x509.h>#include <openssl/pem.h>#include <openssl/ssl.h>#include <openssl/err.h> #pragma comment( lib, "ws2_32.lib" )#pragma comment( lib, "libeay32.lib" )#pragma comment( lib, "ssleay32.lib" )#define MAXBUF 1024#define DEF_IP "127.0.0.1"#define DEF_PORT 7838void ShowCerts(SSL * ssl){ X509 *cert; char *line; cert = SSL_get_peer_certificate(ssl); if (cert != NULL) { printf("數位憑證資訊:\n"); line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0); printf("認證: %s\n", line); OPENSSL_free(line); line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0); printf("頒發者: %s\n", line); OPENSSL_free(line); X509_free(cert); }else printf("無認證資訊!\n");}/************關於本文檔*********************************************filename: ssl-client.c*purpose: 示範利用 OpenSSL 庫進行基於 IP層的 SSL 加密通訊的方法,這是用戶端例子*wrote by: zhoulifa(zhoulifa@163.com) 周立發(http://zhoulifa.bokee.com)Linux愛好者 Linux知識傳播者 SOHO族 開發人員 最擅長C語言*date time:2007-02-02 20:10*Note: 任何人可以任意複製代碼並運用這些文檔,當然包括你的商業用途* 但請遵循GPL*Thanks to:Google*Hope:希望越來越多的人貢獻自己的力量,為科學技術發展出力* 科技站在巨人的肩膀上進步更快!感謝有開源前輩的貢獻!*********************************************************************/int main(){ int sockfd, len; struct sockaddr_in dest; char buffer[MAXBUF + 1]; SSL_CTX *ctx; SSL *ssl; /* 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); }WSADATA wsaData;int ret = WSAStartup( MAKEWORD(2, 2), &wsaData );if ( ret != 0 ) {std::cout<<"WSAStartup error."<<std::endl;return -1;} /* 建立一個 socket 用於 tcp 通訊 */ if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){ perror("Socket"); exit(errno); } printf("socket created\n"); /* 初始化伺服器端(對方)的地址和連接埠資訊 */ memset(&dest,0, sizeof(dest)); dest.sin_family = AF_INET; dest.sin_addr.S_un.S_addr = inet_addr(DEF_IP);dest.sin_port = htons (DEF_PORT); printf("address created\n"); /* 串連伺服器 */ if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0) { perror("Connect "); exit(errno); } printf("server connected\n"); /* 基於 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\n", SSL_get_cipher(ssl)); ShowCerts(ssl); } /* 接收對方發過來的訊息,最多接收 MAXBUF 個位元組 */ memset(buffer,0, MAXBUF + 1); /* 接收伺服器來的訊息 */ len = SSL_read(ssl, buffer, MAXBUF); if (len > 0) printf("接收訊息成功:'%s',共%d個位元組的資料\n",buffer, len); else { printf("訊息接收失敗!錯誤碼是%d,錯誤資訊是'%s'\n",errno, strerror(errno)); goto finish; } memset(buffer, 0,MAXBUF + 1); strcpy(buffer, "from client->server"); /* 發訊息給伺服器 */ len = SSL_write(ssl, buffer, strlen(buffer)); if (len < 0) printf("訊息'%s'發送失敗!錯誤碼是%d,錯誤資訊是'%s'\n",buffer, errno, strerror(errno)); else printf("訊息'%s'發送成功,共發送了%d個位元組!\n",buffer, len); finish: /* 關閉串連 */ SSL_shutdown(ssl); SSL_free(ssl); closesocket(sockfd); SSL_CTX_free(ctx);system("pause"); return 0;}
參考部落格:
Linux網路編程一步一步學-加密通訊協議SSL研究OpenSSL體系下使用密鑰數位憑證openssl使用