1. 程式人生 > >2018-2019-1 20165209 20165215 實驗五 通訊協議設計

2018-2019-1 20165209 20165215 實驗五 通訊協議設計

2018-2019-1 20165209 20165215 實驗五 通訊協議設計


實驗內容

任務一

  1. 兩人一組
  2. 基於Socket實現TCP通訊,一人實現伺服器,一人實現客戶端
    研究OpenSSL演算法,測試對稱演算法中的AES,非對稱演算法中的RSA,Hash演算法中的MD5
  3. 選用合適的演算法,基於混合密碼系統實現對TCP通訊進行機密性、完整性保護。
  4. 學有餘力者,對系統進行安全性分析和改進。

任務二

在Ubuntu中實現對實驗二中的“wc伺服器”通過混合密碼系統進行防護

實驗步驟

任務一

Linux下OpenSSL的安裝與測試

  • 下載openssl-1.1.0j
  • 解壓openssl-1.1.0j :tar xzvf openssl-1.1.0j.tar.gz
  • 進入原始碼目錄:cd openssl-1.1.0-pre1
  • 編譯安裝:
./config
$ make
$ make test
$ make install
  • 編寫測試程式碼test_openssl.c
 #include <stdio.h>
      #include <openssl/evp.h>
      int main(){
         OpenSSL_add_all_algorithms();
         return 0;
      }
  • 編譯生成可執行檔案test_openssl:-o test_openssl test_openssl.c -L/usr/local/ssl/lib -lcrypto -ldl -lpthread

[注]:-L選項——指定連結庫的資料夾地址;-lcrypto——匯入OpenSSL所需包;-ldl選項——載入動態庫;-lpthread選項——連結POSIX thread庫

  • 執行./test_openssl;echo $?,結果正確顯示0

測試AES演算法

  • 相關知識
    • 設定加密金鑰:int AES_set_encrypt_key(const unsigned char *userKey, const int bits,AES_KEY *key);
    • 設定解密金鑰:int AES_set_decrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key);
    • 對資料進行加解密:AES_ecb_encrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key, const int enc);
  • 測試結果如下:

測試RSA演算法

  • 相關知識
    • 生成一個金鑰:openssl genrsa -out prikey.pem 1024,這個檔案包含了公鑰和金鑰兩部分,-out指定生成的檔名,後面的1024是生成金鑰的長度
    • 分離出公鑰:openssl rsa -in prikey.pem -pubout -out pubkey.pem,其中-in指定輸入檔案
    • 用公鑰對檔案加密:openssl rsautl -encrypt -pubin -inkey pubkey.pem -in a.text -out b.text
    • 用私鑰解密:openssl rsautl -decrypt -inkey prikey.pem -in b.text
  • 測試結果如下:

測試MD5演算法

  • 相關知識:
    • 初始化MD5上下文結構:int MD5_Init(MD5_CTX *c);
    • 重新整理MD5,將檔案連續資料分片放入進行MD5重新整理:int MD5_Update(MD5_CTX *c, const void *data, size_t len);
    • 產生最終的MD5資料:int MD5_Final(unsigned char *md, MD5_CTX *c);
    • 直接產生字串的MD5:unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md);
  • 測試結果如下:

實現TCP通訊

任務二

相關知識

  • OpenSSL函式介紹:OpenSSL是一個開放原始碼的SSL協議的產品實現,它採用C語言作為開發語言,具備了跨系統的效能。呼叫OpenSSL的函式就可以實現一個SSL加密的安全資料傳輸通道,從而保護客戶端和伺服器之間資料的安全。
    • 標頭檔案:
    #include <openssl/ssl.h>
    #include <openssl/err.h>
  • 基於OpenSSL的程式都要遵循以下幾個步驟:
    • OpenSSL初始化::在使用OpenSSL之前,必須進行相應的協議初始化工作,可以通過int SSL_library_int(void);實現
    • 選擇會話協議:在利用OpenSSL開始SSL會話之前,需要為客戶端和伺服器制定本次會話採用的協議,目前能夠使用的協議包括TLSv1.0、SSLv2、SSLv3、SSLv2/v3。
    • 建立會話環境:在OpenSSL中建立的SSL會話環境稱為CTX,使用不同的協議會話,其環境也不一樣的。
      • 申請SSL會話環境的OpenSSL函式是:SSL_CTX *SSL_CTX_new(SSL_METHOD * method);
      • 制定證書驗證方式的函式是:int SSL_CTX_set_verify(SSL_CTX *ctx,int mode,int(*verify_callback),int(X509_STORE_CTX *));
      • 為SSL會話環境載入CA證書的函式是:SSL_CTX_load_verify_location(SSL_CTX *ctx,const char *Cafile,const char *Capath);
      • 為SSL會話載入使用者證書的函式是:SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file,int type);
      • 為SSL會話載入使用者私鑰的函式是:SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx,const char* file,int type);
      • 在將證書和私鑰載入到SSL會話環境之後,就可以呼叫int SSL_CTX_check_private_key(SSL_CTX *ctx);來驗證私鑰和證書是否相符:
    • 建立SSL套接字
      • SSL套接字是建立在普通的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握手
      • 在成功建立SSL套接字後,客戶端應使用函式SSL_connect( )來完成握手過程:int SSL_connect(SSL *ssl);
      • 對伺服器來講,使用函式SSL_ accept ( )來完成握手過程:int SSL_accept(SSL *ssl);
      • 握手過程完成之後,通常需要詢問通訊雙方的證書資訊,以便進行相應的驗證,這可以藉助於X509 *SSL_get_peer_certificate(SSL *ssl);來實現
      • 使用X509_NAME *X509_get_subject_name(X509 *a);得到證書所用者的名字
    • 進行資料傳輸

      • 當SSL握手完成之後,就可以進行安全的資料傳輸了,在資料傳輸階段,需要使用SSL_read( )和SSL_write( )來替代傳統的read( )和write( )函式,來完成對套接字的讀寫操作:
      int SSL_read(SSL *ssl,void *buf,int num);
      int SSL_write(SSL *ssl,const void *buf,int num);
    • 結束SSL通訊

      • 當客戶端和伺服器之間的資料通訊完成之後,呼叫下面的函式來釋放已經申請的SSL資源:
      int SSL_shutdown(SSL *ssl);//關閉SSL套接字
      void SSl_free(SSL *ssl);//釋放SSL套接字
      void SSL_CTX_free(SSL_CTX *ctx); //釋放SSL會話環境

執行

  • 編譯方式:
gcc -o server server.c -I /usr/local/ssl/include -L/usr/local/ssl/lib -lssl -lcrypto -ldl -lpthread

gcc -o telent telent.c -I /usr/local/ssl/include -L/usr/local/ssl/lib -lssl -lcrypto -ldl -lpthread
  • 生產私鑰和證書
openssl genrsa -out privkey.pem 1024

openssl req -new -x509 -key privkey.pem -out CAcert.pem -days 1095
  • 程式執行方式:
./server 1509 1 CAcert.pem privkey.pem
./telent 127.0.0.1 1509
  • 截圖

遇到的問題及解決方法

  • 問題一:執行./test_openssl;echo $?,結果顯示錯誤

  • 解決方法:在/usr/local/ssl路徑下建立lib資料夾,然後把openssl_1.1.0j目錄下所有*.a檔案複製到/usr/local/ssl/lib路徑下

  • 問題二:無法生成RSA金鑰

  • 解決方法:輸入命令sudo ln -s /usr/local/lib/libssl.so.1.1 /usr/lib/libssl.so.1.1sudo ln -s /usr/local/lib/libcrypto.so.1.1 /usr/lib/libcrypto.so.1.1後即可生成