密碼學總結

根據網上資料總結而成!~

密碼學總結

作業要求

  • 根據本學期學習過的密碼學知識,利用openssl,自己設計一套加密通訊的方案,實現客戶端和服務端之間的安全的可靠的加密通訊,形式不限,提供實現代碼和實驗結果,最終形成實驗報告

設計思路

首先,任何一套安全的通訊系統在數據傳輸過程中至少具備以下三個特性:

  • 驗證來源的合法性
  • 保證數據的完整性
  • 保證數據的私密性

根據所有加密傳輸的方法,總共有這幾種加密方式

對數據的私密性要求,我們可以通過對數據進行加解密來完成。
如下圖所示:
這裏寫圖片描述
根據加解密Key的不同將加密體系分爲兩種:

1,對稱加密
   特點:使用同一個密鑰進行加解密
   優點: 加密速度快
   缺點:祕鑰傳遞問題
   常見的對稱加密算法有:DES,3DES,AES等
2,非對稱加密
   特點:數據傳輸雙方事先都必須產生一對密鑰
   一個稱爲公鑰
   一個稱爲私鑰
   公鑰加密的數據,只有對應的私鑰才能解密
   私鑰加密的數據,只有對應的公鑰才能解密
   優點:解決了祕鑰傳遞問題 
   缺點:加密速度慢  
   常見的非對稱加密算法有:RSA,DH等

對稱加密:

這裏寫圖片描述

發送方利用自己的密鑰對明文數據進行加密;
接收方必須得到發送方的密鑰;
接收方利用發送方的密鑰對密文進行解密;
如果密鑰在傳輸過程中被第三方獲悉,那此次加密的私密性得不得保障。

非對稱加密:

這裏寫圖片描述

首先通訊雙方都產生一對密鑰;
數據發送方得到數據接收方的公鑰;
數據發送方利用數據接收方的公鑰對數據進行加密;
數據接收方利用自己的私鑰對加密數據進行解密;
數據接收方最終得到明文的數據。
任何一方得到接收方的公鑰,也解密不了傳輸中的數據。
總結:雖然非對稱加密體系實現了密鑰交換的問題,但其本身算法實現複雜導致其加密速度慢。
於是在使用中,人們一般將對稱加密和非對稱加密二者結合起來使用。

對稱與非對稱結合:

混合使用之加密圖解:
這裏寫圖片描述

首先發送方利用一個隨機數產生了一個對稱密鑰;
發送方利用這個密鑰對數據進行加密;
發送方拿着接收方的公鑰對這個密鑰進行加密;
發送方將加密好的數據和加密好的密鑰發送給接收方;
這種方法既保證了加密速度,又保證了加密密鑰的安全傳送。

混合使用之解密圖解:
這裏寫圖片描述

接收方接收到加密的數據和加密的密鑰;
接收方利用自己的私鑰解密加密的密鑰;
接收方再利用已解密的密鑰來解密加密的數據文件;
接收方最終得到了明文的數據。
總結:雖然混合使用對稱加密和非對稱加密之後,既保證了加密速度,又保證了加密密鑰的安全傳送。
但是始終沒辦法保證來源的合法性。這時候就需要用到數字簽名。

數字簽名:

這裏寫圖片描述

發送方使用自己的私鑰加密數據文件(數字簽名);
接收方接收到這個數字簽名文件;
接收方使用發送方的公鑰來解密這個數字簽名文件;
如果能夠解開,則表明這個文件是發送方發送過來的;
否則爲僞造的第三方發送過來的。
對於發送方來講這種簽名有不可否認性。
總結:非對稱加密中,公鑰加密,私鑰解密。主要用來進行數據加密。私鑰加密,公鑰解密。主要用來進行數字簽名和認證。
解決了數據傳輸過程中數據私密性和來源合法性的問題。但對於數據的完整性就需要利用散列函數來實現。

散列函數:

散列函數的特點:

  • 輸入可以是任意長度 但輸出是定長的。MD5 128bits SHA1 160bits
  • 加密過程不可逆,無法根據特徵碼還原原來的數據
  • 雪崩效應 輸入的一點點改變 會導致結果發生很大改變
  • 輸入一致,輸出必然相同
  • 注:不同的輸入,可能會有同樣的輸出。但是概率很小 並不代表沒有這種可能

常見的散列函數(Hash函數):
1,MD5
2,SHA1

總結:散列函數可以根據任意長度的輸入,生成定長的摘要信息。這樣可以用來校驗文件的完整性。防止數據在傳輸過程中被第三方篡改。

安全數字簽名:

這裏寫圖片描述

發送方利用散列函數對明文數據進行Hash得到摘要信息;
發送方使用自己的私鑰對摘要信息進行簽名;
接收方利用發送方的公鑰來驗證來源的合法性;
接收方利用摘要信息來驗證數據的完整性;
當源文件很大,如果對源文件進行簽名,就會比較耗費時間。
如果只對摘要信息進行簽名,速度比較快,因爲它是定長的且位數不長。

中間人攻擊:

利用散列函數我們可以用來保證數據的完整性。使用對稱加密和非對稱加密體系來完成數據的機密性和驗證來源的合法性。但驗證來源的合法性其實存在一個缺陷,就是怎麼保證公鑰的合法性?
這裏寫圖片描述

假設Alice想向Bob發送一個文件。
首先Alice得得到Bob的公鑰;
但是很不幸,Alice得到的是Hacker使用自己的公鑰僞裝成Bob的公鑰;
於是Alice拿着這個僞裝的公鑰對文件進行加密,併發送給Bob;
但不幸的事情又發生了,這個加密文件被Hacker截獲;
於是,Hacker得到了文件的內容;
Hacker對原文件可能進行篡改/也可能不會篡改;
於是Hacker利用Bob真正的公鑰對文件進行加密;
然後發送給Bob;
整個過程對Bob和Alice來說全然無知。

通過上圖,我們看出要想實現對公鑰來源合法性進行驗證。需要數據通訊雙方都得信任這個角色並且這個角色可以幫助通訊雙方安全完成公鑰交換。我們通常把這樣一個角色或機構稱爲CA。

CA數字簽名:

這裏寫圖片描述

  • 首先必須保證CA爲數據通訊雙方都認可的機構;
  • 數據通訊雙方向CA提交認證申請。裏面包含各自的公鑰;
  • CA分別對通訊雙方的合法性進行驗證;
  • 如果驗證通過,CA則利用自己的私鑰分別對兩份申請文件進行加密(數字簽名)。最終產生一個由CA完成數字簽名的文件,稱爲數字證書。
  • 通訊雙方各自下載由CA簽發的數字證書;
  • 假設Alice想要發送一個文件給Bob;
  • 首先Alice得向Bob請求得到Bob的數字證書;
  • Alice利用CA的公鑰完成對Bob數字證書合法性認證,並且從證書中得到Bob的公鑰。
  • Alice利用散列函數對數據進行Hash產生摘要信息;
  • 並通過程序隨機生成一個session key,利用這個session key對數據進行加密;
  • Alice再利用Bob的公鑰對這個session key進行加密;
  • Alice將自己的證書和加密後的文件(包含session key)一併發送給Bob;
  • Bob接收到Alice發來的文件後,先用CA的公鑰來驗證文件來源的合法性。
  • 如果合法,則利用自己的私鑰對session key進行解密,再利用session key對數據進行解密,得到明文數據。
  • 然後,利用散列函數對數據進行Hash得到摘要信息。
  • 將自己得到的摘要信息和Alice發過來的摘要信息進行比對,如果一致,則表明數據沒有被篡改。安全通訊完成。

最終想法

  目前在互聯網上很多Web應用,尤其是那些電子商務應用,如網上銀行,網上超市,股票和債券的在線交易以及軟件的付費下載等,都需要在Web服務器和客戶端瀏覽器之間傳輸機密敏感數據,這些數據包括了信用卡號,密碼,銀行帳號等高度私隱數據,如果這些數據給別人截獲或篡改就會對客戶和網站造成不可估量的損失。
  爲了保護這些敏感數據在傳送過程中的安全,全球許多知名企業採用SSL的加密機制。 SSL是Netscape公司所提出來的安全保密協議,在瀏覽器和WWW服務器之間構造的安全通道來進行數據傳輸,SSL運行在TCP/IP層之上、應用層之下,爲應用程序提供加密數據通道,它採用了RC4、MD5,以及RSA等加密演算法,使用40位的密鑰,合適與對於商業信息的加密。
  根據這一系列分析流程,我準備嘗試進行利用openssl中的SSL系列函數進行加密通信。

這裏寫圖片描述

SSL協議庫

  OpenSSL的SSL協議庫實現了SSL 2.0、SSL 3.0和TLS 1.0。該庫提供了豐富的API函數,這些API函數將SSL協議的處理細節進行了完美的封裝。

實驗過程

這裏寫圖片描述

OpenSSL初始化

OpenSSL在使用之前,必須進行相應的初始化工作。

void SSL_load_error_strings(void); // 錯誤信息的初始化  
int SSL_library_int(void);         // 初始化SSL算法庫函數( 加載要用到的算法 ),調用SSL函數之前必須調用此函數  

在建立SSL連接之前,要爲Client和Server分別指定本次連接採用的協議及其版本,目前能夠使用的協議版本包括SSLv2、SSLv3、SSLv2/v3和TLSv1.0。SSL連接若要正常建立,則要求Client和Server必須使用相互兼容的協議。

創建CTX

在OpenSSL中,CTX是指SSL會話環境。建立連接時使用不同的協議,其CTX也不一樣。

//客戶端、服務端都需要調用的  
SSL_CTX_new()         //申請SSL會話環境  
//若有驗證對方證書的需求,則需調用  
SSL_CTX_set_verify()            //指定證書驗證方式  
SSL_CTX_load_verify_location()  //爲SSL會話環境加載本應用所信任的CA證書列表  
//若有加載證書的需求,則需調用  
SSL_CTX_use_certificate_file()       //爲SSL會話加載本應用的證書  
SSL_CTX_use_certificate_chain_file() //爲SSL會話加載本應用的證書所屬的證書鏈  
SSL_CTX_use_PrivateKey_file()        //爲SSL會話加載本應用的私鑰  
SSL_CTX_check_private_key()          //驗證所加載的私鑰和證書是否相匹配  

創建SSL套接字

在此之前要先創建普通的流套接字,完成TCP三次握手,建立普通的TCP連接。然後創建SSL套接字,並將之與流套接字綁定。

SSL *SSl_new(SSL_CTX *ctx);  //創建一個SSL套接字  
int SSL_set_fd(SSL *ssl,int fd);   //以讀寫模式綁定流套接字  
int SSL_set_rfd(SSL *ssl,int fd);  //以只讀模式綁定流套接字  
int SSL_set_wfd(SSL *ssl,int fd);  //以只寫模式綁定流套接字  

完成SSL握手

在普通TCP連接的基礎上,建立SSL連接。與普通流套接字建立連接的過程類似:Client使用函數SSL_connect()【類似於流套接字中用的connect()】發起握手,而Server使用函數SSL_ accept()【類似於流套接字中用的accept()】對握手進行響應,從而完成握手過程。

int SSL_connect(SSL *ssl);  
int SSL_accept(SSL *ssl);  

握手過程完成之後,Client通常會要求Server發送證書信息,以便對Server進行鑑別。

X509 *SSL_get_peer_certificate(SSL *ssl);  //從SSL套接字中獲取對方的證書信息  
X509_NAME *X509_get_subject_name(X509 *a); //得到證書所用者的名字  

進行數據傳輸

經過前面的一系列過程後,就可以進行安全的數據傳輸了。在數據傳輸階段,需要使用SSL_read( )和SSL_write( )來代替普通流套接字所使用的read( )和write( )函數,以此完成對SSL套接字的讀寫操作

int SSL_read(SSL *ssl,void *buf,int num);            //從SSL套接字讀取數據  
int SSL_write(SSL *ssl,const void *buf,int num);     //向SSL套接字寫入數據  

會話結束

當Client和Server之間的通信過程完成後,就使用以下函數來釋放前面過程中申請的SSL資源

int SSL_shutdown(SSL *ssl);       //關閉SSL套接字  
void SSl_free(SSL *ssl);          //釋放SSL套接字  
void SSL_CTX_free(SSL_CTX *ctx);  //釋放SSL會話環境  

通過利用上述函數在結合TCP連接所需要的相關語句,最終形成代碼

截圖

這裏寫圖片描述

總結

  • 首先就是證書的生成問題,windows下沒有生成成功,最後利用ubuntu系統一系列命令才進行生成並且簽名成功。
  • 關於環境的配置問題,在執行SSL_connect和SSL_accept進行交互時發生錯誤,更改TSLv1、SSLv2、SSLv3、SSLv23時發生要麼是連接錯誤,要麼是接受錯誤,自己分析應該是配置環境時缺少相應的動態鏈接庫或相應執行文件
  • openssl雖然是開源密碼庫,涵括非常多的加解密算法,便利書寫代碼,但一定程度上也弱化了對密碼的理解能力,甚至包含漏洞而無法發現造成損失
  • 針對於通信加密問題,加密方式很多但重點不在於如何編寫XX加密,而是在於如何去組合運用,使得通信更加安全穩定
  • 此次作業讓我較爲深刻的理解SSL加密通信的原理,如何去運用,如何使得自己的信息更加安全

源代碼

server

#include <iostream>
#include <openssl/rsa.h> 
#include <openssl/crypto.h> 
#include <openssl/x509.h>
#include <openssl/pem.h> 
#include <openssl/ssl.h>  
#include <openssl/err.h>  
#include <openssl/rand.h>  

using namespace std;  

#pragma comment(lib, "libeay32.lib")  
#pragma comment(lib, "ssleay32.lib")  
#pragma comment(lib, "ws2_32.lib")

#define CERTF "server.crt" //客戶端的證書(需經CA簽名)
#define KEYF "server.key" //客戶端的私鑰  
#define CACERT "ca.crt" //CA 的證書
#define PORT 4000 
#define IP_ADDRESS "127.0.0.1"

#define MAXLEN 4096   

int main()  
{  
    int iResult;  
    int ListenSock;//監聽套接字  
    int ConnectSock;//連接套接字  
    SSL_CTX *ctx;  
    SSL *ssl;  
    X509 *client_cert;  
    char buf [MAXLEN] = {0};  
    SSL_METHOD *meth;  

    WSADATA wsaData;  
    if(WSAStartup(MAKEWORD(2,2),&wsaData) != 0)
    {  
        cout<<"Init Windows Socket Failed::"<<GetLastError()<<endl;
        return -1;  
    }   

    SSL_library_init();
    OpenSSL_add_ssl_algorithms(); //初始化* 
    SSL_load_error_strings(); //爲打印調試信息作準備

    meth=(SSL_METHOD *)SSLv23_server_method();  
    ctx = SSL_CTX_new (meth); //採用什麼協議(SSLv2/SSLv3/TLSv1)在此指定  
    if(ctx == NULL) 
    { 
        cout<<"null"<<endl; 
    } 

    SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL); //驗證與否
    SSL_CTX_load_verify_locations(ctx,CACERT,NULL); //若驗證,則放置CA證書  

    if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0)   
    {  
        cout<<"服務器端證書檢查失敗!"<<endl;  
        exit(0);  
    }  
    if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0)   
    {  
        cout <<"服務器端key檢查失敗!"<<endl;  
        system("pause");  
        exit(0);  
    }  
    else  
    {  
        cout<<"服務器端key檢查成功!"<<endl;  
    }  

    if (!SSL_CTX_check_private_key(ctx))   
    {  
        cout << "服務器端證書和key不匹配!"<<endl;  
        exit(0);  
    }  

    SSL_CTX_set_cipher_list(ctx,"RC4-MD5");
     //SSL_CTX_set_cipher_list(ctx, "AES128-SHA");  
    SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); //不需要任何重試請求  

    //創建監聽套接字  
    ListenSock = socket (AF_INET, SOCK_STREAM, 0);   
    if(ListenSock == INVALID_SOCKET)  
    {  
        cout << "監聽套接字創建失敗" << endl;  
        exit(0);  
    }    
     //創建地址  
     struct sockaddr_in LocalAddr;  
     LocalAddr.sin_family = AF_INET;  
     //LocalAddr.sin_addr.s_addr = INADDR_ANY;  
     LocalAddr.sin_addr.s_addr = inet_addr (IP_ADDRESS);
     LocalAddr.sin_port = htons (PORT); 
     memset(LocalAddr.sin_zero,0x00,8);
     //套接字綁定  
     iResult = bind(ListenSock, (struct sockaddr*)&LocalAddr,sizeof(LocalAddr));   
     if(iResult == -1)  
     {  
         cout << "監聽套接字綁定失敗" << endl;  
         exit(0);  
     }  

     /*接受TCP鏈接*/  
     iResult = listen (ListenSock, 10); 
     if(iResult == -1)  
     {  
         cout << "監聽套接字開啓監聽失敗" << endl;  
         exit(0);  
     }  

     //接受客戶端連接  
     struct sockaddr_in ClientSocket;  
     int len=sizeof(struct sockaddr);  
     ConnectSock = accept(ListenSock, (struct sockaddr *)&ClientSocket, &len);  
     if(iResult == -1)  
     {  
         cout << "監聽套接字accept失敗" << endl;  
         exit(0);  
     }  

     cout<<"Connection from "<<inet_ntoa(ClientSocket.sin_addr)<<":"<<ntohs(ClientSocket.sin_port)<<endl;  
     cout<<"------------------TCP連接已建立,進行服務端的SSL過程.---------------"<<endl; 
     cout<<"創建SSL連接中...."<<endl;  
     //從初始化的ctx新建SSL  
     ssl = SSL_new (ctx);   
     if(ssl == NULL)  
     {  
         cout << "SSL創建失敗" << endl;  
         exit(0);  
     }  
     //(連接)套接字和SSL綁定 
     SSL_set_fd (ssl, ConnectSock);  
     //SSL連接建立  
     iResult = SSL_accept (ssl);//等待一個TLS / SSL客戶端啓動TLS / SSL握手,類似於socket中的accept。  
     if(iResult == -1)  
     {  
         cout << "SSL連接失敗" << endl;  
         exit(1);  
     }  
     else  
     {  
         cout << "SSL連接成功" << endl;  
     }  
     //打印所有加密算法的信息  
     cout<<"SSL連接算法信息:"<< SSL_get_cipher (ssl) << endl;   
     //得到客戶端的證書並打印些信息   
     client_cert = SSL_get_peer_certificate (ssl);    
     if (client_cert != NULL) 
     {    
         cout<<"客戶端證書:"<<endl;    
         cout<<"subject:"<<X509_NAME_oneline(X509_get_subject_name (client_cert), 0, 0)<<endl;    
         cout<<"issuer:"<<X509_NAME_oneline(X509_get_issuer_name (client_cert),0,0)<<endl;    
         X509_free (client_cert);//如不再需要,需將證書釋放    
     }    
     else 
     {
        cout<<"客戶端沒有證書信息!"<<endl; //客戶端認證失敗   
     }  
     cout<<"--------------------SSL連接已建立,進行通信會話.--------------------"<<endl;
     //SSL通信 
     while(true)  
     {    
         //接收消息  
         iResult = SSL_read (ssl, buf, sizeof(buf) - 1);   
         if(iResult == -1)  
         {  
             cout<<"接收消息失敗"<<endl;  
             exit(0);  
         }  
         buf[iResult] = '\0';  
         cout<<"client--->"<<buf<<endl;  
         //發送消息  
         cout<<"請輸入要發送的消息:";  
         gets_s(buf);
         iResult = SSL_write(ssl, buf, strlen(buf));  
         if(iResult == -1)  
         {  
             cout<<"SSL_write發送消息失敗"<<endl;  
             exit(0);  
         }  
         cout<<"server--->"<<buf<<endl;  
     }  

     //關閉套接字和ssl  
     SSL_shutdown (ssl);  
     shutdown (ConnectSock,2);  
     SSL_free (ssl);  
     SSL_CTX_free (ctx);  
     closesocket(ConnectSock);  
     return 0;  
} 

client

#include <iostream>
#include <openssl/rsa.h> 
#include <openssl/crypto.h> 
#include <openssl/x509.h>
#include <openssl/pem.h> 
#include <openssl/ssl.h>  
#include <openssl/err.h>  
#include <openssl/rand.h>  

using namespace std;  

#pragma comment(lib, "libeay32.lib")  
#pragma comment(lib, "ssleay32.lib")  
#pragma comment(lib, "ws2_32.lib")  

#define CERTF "client.crt" //客戶端的證書(需經CA簽名)  
#define KEYF "client.key" //客戶端的私鑰  
#define CACERT "ca.crt" //CA 的證書 
#define PORT 4000
#define IP_ADDRESS "127.0.0.1"

#define MAXLEN 4096  

int main()  
{  
    int iResult;  
    int ClientSocket;
    struct sockaddr_in ServerAddr;  
    SSL_CTX *ctx;  
    SSL *ssl;  
    X509 *server_cert;  
    char buf [MAXLEN] = {0};    
    SSL_METHOD *meth;  
    int seed_int[100]; /*存放隨機序列*/  

    WSADATA wsaData;  
    SSL_library_init();
    if(WSAStartup(MAKEWORD(2,2),&wsaData) != 0)
    {  
        cout<<"Init Windows Socket Failed::"<<GetLastError()<<endl; 
        return -1;  
    }    
    OpenSSL_add_ssl_algorithms(); /*1.SSL初始化*/  
    SSL_load_error_strings(); /*2.SSL錯誤信息初始化 爲打印調試信息作準備*/  
    meth=(SSL_METHOD *)SSLv23_client_method();  
    ctx = SSL_CTX_new (meth); //採用什麼協議(SSLv2/SSLv3/TLSv1)在此指定
    if(ctx == NULL) 
    { 
        cout<<"null"<<endl; 
    }   
    //SSL_VERIFY_PEER:希望驗證對方的證書  
    SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL); /*驗證與否*/  //5.設置會話的握手方式  
    SSL_CTX_load_verify_locations(ctx,CACERT,NULL); /*若驗證,則放置CA證書*/  //6.並加載CA證書  

    if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0) //7.加載自己(客戶端)的整數  
    {  
        cout << "客戶端證書檢查失敗!" << endl;  
        exit(0);  
    }  
    if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0) //8.加載客戶端的私鑰  
    {  
        cout << "客戶端key檢查失敗!" << endl;  
        system("pause");  
        exit(0);  
    }  
    else  
    {  
        cout<<"客戶端證key檢查成功!"<<endl;  
    }  

    if (!SSL_CTX_check_private_key(ctx))//9.檢查自己的證書和私鑰是否匹配   
    {  
        cout << "客戶端證書和key不匹配!" << endl;  
        exit(0);  
    }  

     //加密方式    
    SSL_CTX_set_cipher_list(ctx, "RC4-MD5");   
    //SSL_CTX_set_cipher_list(ctx, "AES128-SHA");      
    //設置ssl的模式爲SSL_MODE_AUTO_RETRY,使用這個選項進行設置,如果服務器突然希望進行一次新的握手,那麼OpenSSL可以在後臺處理它。  
    SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);   

    srand( (unsigned)time( NULL ) ); 
    for( int i = 0; i < 100;i++ ) 
    {
        seed_int[i] = rand(); 
    }
    RAND_seed(seed_int, sizeof(seed_int));
    //創建TCP連接請求  
    ClientSocket = socket (AF_INET, SOCK_STREAM, 0);   
    if(ClientSocket == INVALID_SOCKET)  
    {  
        cout << "套接字創建失敗!" << endl;  
        exit(0);  
    }  
    memset(ServerAddr.sin_zero, 0x00, 8); 
    ServerAddr.sin_family = AF_INET;  
    ServerAddr.sin_addr.s_addr = inet_addr ("127.0.0.1");  
    ServerAddr.sin_port = htons (PORT); 
    //TCP連接
    iResult = connect(ClientSocket, (struct sockaddr*) &ServerAddr,sizeof(ServerAddr));  
    if(iResult == -1)  
    {  
        cout << "TCP連接失敗!" << endl;  
    }  
    else  
    {  
        cout << "TCP連接成功!" << endl;  
    }  
    cout<<"------------------TCP連接已建立,進行服務端的SSL過程.---------------"<<endl; 
    cout<<"創建SSL連接中...."<<endl;  
    //新建SSL  
    ssl = SSL_new (ctx);
    if(ssl == NULL)  
    {  
        cout << "新建SSL失敗!" << endl;  
        exit(0);  
    }  
    //套接字ClientSocket和SSL綁定  
    SSL_set_fd (ssl, ClientSocket);   
    iResult = SSL_connect (ssl);  
    if(iResult == -1)  
    {  
        cout<<"SSL連接失敗"<<endl; 
    }      
    else  
    {  
        cout<<"SSL連接成功"<<endl;  
    }  
    //打印連接信息  
    cout<<"SSL連接算法信息:" << SSL_get_cipher (ssl) << endl;  
    //得到服務端的證書並打印些信息  
    server_cert = SSL_get_peer_certificate (ssl);//從SSL套接字中提取對方的證書信息,這些信息已經被SSL驗證過了  
    if (server_cert != NULL) 
    {  
        cout<<"服務器證書:"<<endl;  
        cout<<"subject:"<<X509_NAME_oneline( X509_get_subject_name (server_cert), 0, 0)<<endl;//得到證書所用者的名字  
        cout<<"issuer:"<<X509_NAME_oneline (X509_get_issuer_name (server_cert),0,0)<<endl;    
        X509_free (server_cert);//如不再需要,需將證書釋放   
    }  
    else 
    {
        cout<<"客戶端沒有證書信息!"<<endl; //客戶端認證失敗   
     }     
    cout<<"--------------------SSL連接已建立,進行通信會話.--------------------"<<endl;
    //SSL通信 
    while(true)  
    {    
        cout<<"請輸入要發送的消息:";  
        gets_s(buf);  
        iResult=SSL_write(ssl, buf, strlen(buf));  
        if(iResult == -1)  
        {  
            cout<<"發送消息失敗"<<endl;  
            exit(0);  
        }  
        cout<<"客戶端--->"<<buf<<endl;  
        //接收消息 
        iResult = SSL_read (ssl, buf, sizeof(buf) - 1);   
        if(iResult == -1)  
        {  
            cout<<"SSL_read接收消息失敗"<<endl;  
            exit(0);  
        }  
        buf[iResult] = '\0';  
        cout<<"服務端--->"<<buf<<endl;  
    }  

    SSL_shutdown (ssl);//關閉SSL套接字  
    SSL_free (ssl);//釋放SSL套接字  
    SSL_CTX_free (ctx);//釋放SSL會話環境  
    closesocket(ClientSocket);//  
    return 0;  
}  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章