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会话环境
-
运行
- 编译方式:
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
后即可生成