2018-2019-1 20165209 20165215 實驗五 通訊協議設計
阿新 • • 發佈:2018-12-15
2018-2019-1 20165209 20165215 實驗五 通訊協議設計
實驗內容
任務一
- 兩人一組
- 基於Socket實現TCP通訊,一人實現伺服器,一人實現客戶端
研究OpenSSL演算法,測試對稱演算法中的AES,非對稱演算法中的RSA,Hash演算法中的MD5 - 選用合適的演算法,基於混合密碼系統實現對TCP通訊進行機密性、完整性保護。
- 學有餘力者,對系統進行安全性分析和改進。
任務二
在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);
- 初始化MD5上下文結構:
- 測試結果如下:
實現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會話環境的OpenSSL函式是:
- 建立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握手完成之後,就可以進行安全的資料傳輸了,在資料傳輸階段,需要使用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會話環境
- OpenSSL初始化::在使用OpenSSL之前,必須進行相應的協議初始化工作,可以通過
執行
- 編譯方式:
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.1
和sudo ln -s /usr/local/lib/libcrypto.so.1.1 /usr/lib/libcrypto.so.1.1
後即可生成