2017-2018-1 20155332 实验五 通信协议设计
实验内容
研究OpenSSL算法,测试对称算法中的AES,非对称算法中的RSA,Hash算法中的MD5
选用合适的算法,基于混合密码系统实现对TCP通信进行机密性、完整性保护。
2.在Ubuntu中实现对实验二中的“wc服务器”通过混合密码系统进行防护
实验截图 已经在蓝墨云班课提交
实验步骤
任务一 Linux下OpenSSL的安装与测试
任务要求:在Ubuntu中完成 http://www.cnblogs.com/rocedu/p/5087623.html 中的作业
1.安装指南
到OpenSSL官网,选择打开OpenSSL源码载地址,按照下图所示方法下载压缩包“openssl-master.zip”
2.安装命令
$ ./config
$ make
$ make test
$ make install
3.安装测试
用老师教程中的test_openssl.c例子进行测试
#include <stdio.h>
#include <openssl/evp.h>
int main(){
OpenSSL_add_all_algorithms();
return 0;
}
4.编译运行
使用命令gcc -o test_openssl test_openssl.c -L/usr/local/ssl/lib -lcrypto -ldl -lpthread
编译,结果生成可执行文件test_openssl
并执行echo $?
,结果打印0
,测试结果表明安装成功。
【对编译命令的一点说明:-L选项——指定链接库的文件夹地址;-lcrypto——导入OpenSSL所需包;-ldl选项——加载动态库;-lpthread选项——链接POSIX thread库】
任务二
任务要求:在Ubuntu中实现对实验二中的“wc服务器”通过混合密码系统进行防护
实验步骤
- OpenSSL初始化
- 选择会话协议
- 创建会话环境
- 建立SSL套接字
- 完成SSL握手
- 进行数据传输
- 结束SSL通信
实验代码
#include<netinet/in.h> // for sockaddr_in
#include<sys/types.h> // for socket
#include<sys/socket.h> // for socket
#include<stdio.h> // for printf
#include<stdlib.h> // for exit
#include<string.h> // for bzero
#include<memory.h>
#include<time.h>
#include<openssl/rsa.h>
#include<openssl/pem.h>
#include<openssl/err.h>
#include <openssl/aes.h>
#pragma comment(lib,"libeay32.lib")
#define OPENSSLKEY "test.key"
#define PUBLICKEY "test_pub.key"
#define BUFFSIZE 1024
#define HELLO_WORLD_SERVER_PORT 6000
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512
int mywc(char file_name[],int choose);
char* my_encrypt(char *str,char *path_key);//rsa加密
char* my_decrypt(char *str,char *path_key);//rsa解密
void aes_encrypt(char *str,char aes_keybuf[],char buf[]);//aes加密
void aes_decrypt(char *str,char aes_keybuf[],char buf[]);//aes解密
int main(int argc, char **argv)
{
FILE *fp;
if (argc != 2)
{
printf("Usage: ./%s ServerIPAddress\\n", argv[0]);
exit(1);
}
// 设置一个socket地址结构client_addr, 代表客户机的internet地址和端口
struct sockaddr_in client_addr;
bzero(&client_addr, sizeof(client_addr));
client_addr.sin_family = AF_INET;
client_addr.sin_addr.s_addr = htons(INADDR_ANY); // INADDR_ANY表示自动获取本机地址
client_addr.sin_port = htons(0);
// 创建字节流socket,用client_socket代表客户端socket
int client_socket = socket(AF_INET, SOCK_STREAM, 0);
if (client_socket < 0)
{
printf("Create Socket Failed!\\n");
exit(1);
}
// 把客户端的socket和客户端的socket地址结构绑定
if (bind(client_socket, (struct sockaddr*)&client_addr, sizeof(client_addr)))
{
printf("Client Bind Port Failed!\\n");
exit(1);
}
// 设置一个socket地址结构server_addr,代表服务器的internet地址和端口
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
// 服务器的IP地址来自程序的参数
if (inet_aton(argv[1], &server_addr.sin_addr) == 0) //一个字符串IP地址转换为一个32位的网络序列IP地址,也可以用inet_addr
{
printf("Server IP Address Error!\\n");
exit(1);
}
server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);
int server_addr_length = sizeof(server_addr);
// 向服务器发起连接请求,连接成功后client_socket代表客户端和服务器端的一个socket连接
if (connect(client_socket, (struct sockaddr*)&server_addr, server_addr_length)==-1)
{
printf("Can Not Connect To %s!\\n", argv[1]);
exit(1);
}
char file_name[FILE_NAME_MAX_SIZE];
bzero(file_name, sizeof(file_name));
printf("Please Input File Name.\\t");
scanf("%s", file_name);
if((fp = fopen(file_name,"r"))==NULL)
{
printf("Failure to open %s\\n",file_name);
exit(0);
}
char buffer[BUFFER_SIZE];
bzero(buffer, sizeof(buffer));
strcpy(buffer,file_name);
if(send(client_socket,buffer,BUFFER_SIZE,0)==-1)
{
printf("发送文件名失败\\n");
}
printf("发送文件名成功\\n");
bzero(buffer, sizeof(buffer));
//利用伪随机数生成32字节会话密钥:
unsigned char aes_keybuf[32];
int i;
srand((unsigned) time(NULL));
for(i=0;i<32;i++)
{
aes_keybuf[i]=rand()%10+48;
}
//用rsa对会话密钥加密
char *aeskey_en;
aeskey_en=my_encrypt(aes_keybuf,PUBLICKEY);
printf("会话密钥:%s\\n加密后的会话密钥为%s\\n\\n\\n",aes_keybuf,aeskey_en);
if((send(client_socket, aeskey_en, strlen(aeskey_en)+1, 0))==-1)
{
printf("发送文件失败\\n");
}
printf("发送密钥完毕,长度为%d\\n",strlen(aeskey_en)+1);
printf("是否发送密文?y or n\\n");
char choose;
char ch;while((ch=getchar())!=\'\\n\'&&ch!=EOF);
scanf("%c",&choose);
if(choose==\'y\')
{//使用会话密钥对消息进行aes加密
char ptr_en[512],ptr_de[512];
char ch;
i=0;
while((ch=fgetc(fp))!=EOF)
{
buffer[i++]=ch;
if(i>=BUFFER_SIZE)
{
printf("加密前 %s\\n",buffer);
aes_encrypt(buffer,aes_keybuf,ptr_en);
//printf("加密后发送密文 %s\\n",ptr_en);
if((send(client_socket, ptr_en, strlen(ptr_en), 0))==-1)
{
printf("发送文件失败\\n");
}
printf("发送密文长度 :%d\\n",strlen(ptr_en));
bzero(ptr_en, sizeof(ptr_en));
bzero(buffer, sizeof(buffer));
i=0;
}
}
if(i<BUFFER_SIZE)
{
printf("加密前消息 %s\\n",buffer);
aes_encrypt(buffer,aes_keybuf,ptr_en);
printf("加密后发送密文 %s\\n",ptr_en);
//ptr_de=my_decrypt(buffer,OPENSSLKEY);//解密buffer
if((send(client_socket, ptr_en, strlen(ptr_en), 0))==-1)
{
printf("发送文件失败\\n");
}
printf("发送密文长度 :%d\\n",strlen(ptr_en));
}
bzero(buffer, sizeof(buffer));
printf("发送密文完毕\\n");
}
/*
if(ptr_en!=NULL){
free(ptr_en);
} */
mywc(file_name,1);
mywc(file_name,2);
bzero(buffer, sizeof(buffer));
fclose(fp);
close(client_socket); // 传输完毕,关闭socket
return 0;
}
int mywc(char file_name[],int choose)
{
FILE *fp;
char ch;
int flag=0,num=0;
// int choose;
// printf("统计单词个数还是实现“wc -w”?(1or2)\\n");
// scanf("%d",&choose);
if((fp = fopen(file_name,"r"))==NULL)
{
printf("Failure to open %s\\n",file_name);
exit(0);
}
if(choose==1)
{
while((ch=fgetc(fp))!=EOF)
{
if(ch==\' \' || ch==\'\\n\' || ch==\'\\t\' || ch==\'\\!\' || ch==\'\\?\' || ch==\'\\"\' || ch==\'\\.\' || ch== \'\\,\' || ch==\'\\:\' || ch==\'\\(\' || ch==\'\\)\' || ch==\'\\;\' || ch==\'\\-\')
{
flag=0;
}
else
{
if(flag==0)
{
flag=1;
num++;
}
}
}
}
else if(choose==2)
{
while((ch=fgetc(fp))!=EOF)
{
if(ch==\' \' || ch==\'\\n\' || ch==\'\\t\' || ch==\'\\r\')
flag=0;
else
{
if(flag==0)
{
flag=1;
num++;
}
}
}
}
printf("单词个数为:%d_用方式%d计算\\n",num,choose);
fclose(fp);
return num;
}
char *my_encrypt(char *str,char *path_key){
char *p_en;
RSA *p_rsa;
FILE *file;
int flen,rsa_len;
if((file=fopen(path_key,"r"))==NULL){
perror("open key file error");
return NULL;
}
if((p_rsa=PEM_read_RSA_PUBKEY(file,NULL,NULL,NULL))==NULL){
//if((p_rsa=PEM_read_RSAPublicKey(file,NULL,NULL,NULL))==NULL){ 换成这句死活通不过,无论是否将公钥分离源文件
ERR_print_errors_fp(stdout);
return NULL;
}
flen=strlen(str);
rsa_len=RSA_size(p_rsa);
p_en=(unsigned char *)malloc(rsa_len+1);
memset(p_en,0,rsa_len+1);
if(RSA_public_encrypt(rsa_len,(unsigned char *)str,(unsigned char*)p_en,p_rsa,RSA_NO_PADDING)<0){
return NULL;
}
RSA_free(p_rsa);
fclose(file);
return p_en;
}
char *my_decrypt(char *str,char *path_key){
char *p_de;
RSA *p_rsa;
FILE *file;
int rsa_len;
if((file=fopen(path_key,"r"))==NULL){
perror("open key file error");
return NULL;
}
if((p_rsa=PEM_read_RSAPrivateKey(file,NULL,NULL,NULL))==NULL){
ERR_print_errors_fp(stdout);
return NULL;
}
rsa_len=RSA_size(p_rsa);
p_de=(unsigned char *)malloc(rsa_len+1);
memset(p_de,0,rsa_len+1);
if(RSA_private_decrypt(rsa_len,(unsigned char *)str,(unsigned char*)p_de,p_rsa,RSA_NO_PADDING)<0){
return NULL;
}
RSA_free(p_rsa);
fclose(file);
return p_de;
}
void aes_encrypt(char *str,char aes_keybuf[],char buf[]){
AES_KEY aeskey;
AES_set_encrypt_key(aes_keybuf,256,&aeskey);
for(int i=0;i<sizeof(str);i+=16)
AES_encrypt(str+i,buf+i,&aeskey);
//printf("\\n\\nin_加密后:%s\\n\\n\\n",buf);
}
void aes_decrypt(char *str,char aes_keybuf[],char buf[]){
AES_KEY aeskey;
AES_set_decrypt_key(aes_keybuf,256,&aeskey);
for(int i=0;i<sizeof(str);i+=16)
AES_decrypt(str+i,buf+i,&aeskey);
}
#include<netinet/in.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
#include<memory.h>
#include<openssl/rsa.h>
#include<openssl/pem.h>
#include<openssl/err.h>
#include <openssl/aes.h>
#pragma comment(lib,"libeay32.lib")
#define OPENSSLKEY "test.key"
#define PUBLICKEY "test_pub.key"
#define BUFFSIZE 1024
#define HELLO_WORLD_SERVER_PORT 6000
#define LENGTH_OF_LISTEN_QUEUE 20
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512
char* my_encrypt(char *str,char *path_key);//rsa加密
char* my_decrypt(char *str,char *path_key);//rsa解密
void aes_encrypt(char *str,char aes_keybuf[],char buf[]);//aes加密
void aes_decrypt(char *str,char aes_keybuf[],char buf[]);//aes解密
void *process_client(void *new_server_socket);
int mywc(char file_name[])
{
char ch;
int flag=0,num=0;
int choose;
FILE *fp;
printf("统计单词个数还是实现“wc -w”?(1or2)\\n");
scanf("%d",&choose);
if((fp = fopen(file_name,"r"))==NULL)
{
printf("Failure to open %s\\n",file_name);
exit(0);
}
if(choose==1)
{
while((ch=fgetc(fp))!=EOF)
{
if(ch==\' \' || ch==\'\\n\' || ch==\'\\t\' || ch==\'\\!\' || ch==\'\\?\' || ch==\'\\"\' || ch==\'\\.\' || ch== \'\\,\' || ch==\'\\:\' || ch==\'\\(\' || ch==\'\\)\' || ch==\'\\;\' || ch==\'\\-\')
{
flag=0;
}
else
{
if(flag==0)
{
flag=1;
num++;
}
}
}
}
else if(choose==2)
{
while((ch=fgetc(fp))!=EOF)
{
if(ch==\' \' || ch==\'\\n\' || ch==\'\\t\' || ch==\'\\r\')
flag=0;
else
{
if(flag==0)
{
flag=1;
num++;
}
}
}
}
printf("单词个数为:%d\\n",num);
fclose(fp);
return num;
}
int main(int argc, char **argv)
{
// 设置一个socket地址结构server_addr,代表服务器的IP地址和端口
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htons(INADDR_ANY);
server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);
// 创建字节流socket:server_socket
int server_socket = socket(AF_INET, SOCK_STREAM, 0);
if (server_socket ==-1)
{
printf("Create Socket Failed!\\n");
exit(1);
}
// 把socket和socket地址结构绑定
if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr))==-1)
{
printf("Server Bind Port: %d Failed!\\n", HELLO_WORLD_SERVER_PORT);
exit(1);
}
// server_socket用于监听
if (listen(server_socket, LENGTH_OF_LISTEN_QUEUE)==-1)
{
printf("Server Listen Failed!\\n");
exit(1);
}
// 服务器端一直运行用以持续为客户端提供服务
while(1)
{
// 定义客户端的socket地址结构client_addr,当收到来自客户端的请求后,调用accept
struct sockaddr_in client_addr;
int length = sizeof(client_addr);
// accpet返回一个新的socket,这个socket用来与此次连接到server的client进行通信
int new_server_socket = accept(server_socket, (struct sockaddr*)&client_addr, &length);
if (new_server_socket ==-1)
{
printf("Server Accept Failed!\\n");
exit(0);
}
printf("连接到客户端\\n");
pthread_t pid;
if(pthread_create(&pid, NULL, process_client,(void *) &new_server_socket) < 0){
printf("pthread_create error\\n");
}
}
// close(server_socket);
}
void *process_client(void *new_server_socket)
{
int sockid=*(int *)new_server_socket;
FILE *fp;
//接受来自客户端的文件
char buffer[BUFFER_SIZE];
char file_name[FILE_NAME_MAX_SIZE];
bzero(buffer, sizeof(buffer));
int length=0;
if(recv(sockid,buffer,BUFFER_SIZE, 0)==-1)
{
printf("接受文件名%s失败\\n",buffer);
}
strcpy(file_name,buffer);
strcat(file_name,"_server");
printf("创建文件夹%s\\n",file_name);
if((fp = fopen(file_name,"w"))==NULL)
{
printf("Failure to open %s\\n",file_name);
exit(0);
}
bzero(buffer, sizeof(buffer));
//接收密钥密文
unsigned char *aes_keybuf;
int lenn;
if((lenn=recv(sockid, buffer,BUFFER_SIZE, 0))<0)
{
printf("接受密钥出错\\n");
}
printf("接受密钥密文 %s\\n\\n",buffer);
printf("接受密钥length %d\\n\\n",lenn);
aes_keybuf=my_decrypt(buffer,OPENSSLKEY);//解密buffer
printf("解密得会话密钥 %s\\n\\n\\n",aes_keybuf);
bzero(buffer, sizeof(buffer));
char ptr_en[512],ptr_de[512];
//length = recv(sockid, buffer,BUFFER_SIZE, 0);
//printf(" recv length :%d\\n",length);
while( length = recv(sockid, buffer,BUFFER_SIZE, 0))
{
if(length<0)
{
printf("接受文件出错\\n");
exit(0);
}
printf("接受密文 %s\\n\\n\\n",buffer);
aes_decrypt(buffer,aes_keybuf,ptr_de);//解密buffer
printf("解密密文 %s\\n",ptr_de);
fwrite(ptr_de,sizeof(char),strlen(ptr_de),fp)<length;
bzero(buffer, sizeof(buffer));
bzero(ptr_de, sizeof(ptr_de));
}
fclose(fp);
/*if(ptr_de!=NULL){
free(ptr_de);
} */
printf("接收密文完毕\\n");
bzero(buffer, BUFFER_SIZE);
int number=0;
number=mywc(file_name);
//bzero(buffer, BUFFER_SIZE);
//buffer[0]=number+48;
bzero(buffer, sizeof(buffer));
printf("File Transfer Finished!\\n");
close(new_server_socket);
}
char *my_encrypt(char *str,char *path_key){
char *p_en;
RSA *p_rsa;
FILE *file;
int flen,rsa_len;
if((file=fopen(path_key,"r"))==NULL){
perror("open key file error");
return NULL;
}
if((p_rsa=PEM_read_RSA_PUBKEY(file,NULL,NULL,NULL))==NULL){
//if((p_rsa=PEM_read_RSAPublicKey(file,NULL,NULL,NULL))==NULL){ 换成这句死活通不过,无论是否将公钥分离源文件
ERR_print_errors_fp(stdout);
return NULL;
}
flen=strlen(str);
rsa_len=RSA_size(p_rsa);
p_en=(unsigned char *)malloc(rsa_len+1);
memset(p_en,0,rsa_len+1);
if(RSA_public_encrypt(rsa_len,(unsigned char *)str,(unsigned char*)p_en,p_rsa,RSA_NO_PADDING)<0){
return NULL;
}
RSA_free(p_rsa);
fclose(file);
return p_en;
}
char *my_decrypt(char *str,char *path_key){
char *p_de;
RSA *p_rsa;
FILE *file;
int rsa_len;
if((file=fopen(path_key,"r"))==NULL){
perror("open key file error");
return NULL;
}
if((p_rsa=PEM_read_RSAPrivateKey(file,NULL,NULL,NULL))==NULL){
ERR_print_errors_fp(stdout);
return NULL;
}
rsa_len=RSA_size(p_rsa);
p_de=(unsigned char *)malloc(rsa_len+1);
memset(p_de,0,rsa_len+1);
if(RSA_private_decrypt(rsa_len,(unsigned char *)str,(unsigned char*)p_de,p_rsa,RSA_NO_PADDING)<0){
return NULL;
}
RSA_free(p_rsa);
fclose(file);
return p_de;
}
void aes_encrypt(char *str,char aes_keybuf[],char buf[]){
AES_KEY aeskey;
AES_set_encrypt_key(aes_keybuf,256,&aeskey);
for(int i=0;i<sizeof(str);i+=16)
AES_encrypt(str+i,buf+i,&aeskey);
}
void aes_decrypt(char *str,char aes_keybuf[],char buf[]){
AES_KEY aeskey;
AES_set_decrypt_key(aes_keybuf,256,&aeskey);
for(int i=0;i<sizeof(str);i+=16)
AES_decrypt(str+i,buf+i,&aeskey);
}