网络通信加密

对传输的数据包进行加密,在tcp层之上,应用层之下进行。在利用网络传输之前,对传输的数据进行混淆。防止中间人拦截,摧毁外挂。
有三种方案:

1. 自己实现对称加密算法,将数据包的内容进行加密。

  • 通常做法是按字节或者按位进行运算,本质上是对字符串进行运算,将字符串作为参数,进行运算后产生新的内容然后发送。
  • 加密和解密的效率,以及破解的难度,与字符串运算的算法有关。但实现起来相对比较容易,bug排查也易于进行。

2. 利用第三方的对称加密算法,客户端和服务器端利用相同的密钥进行加密。

  • 此方法的所有数据包的加密和解密密钥相同,相同数据包,经过相同密钥加密后,产生的内容也相同。
  • 算法对称,密钥固定,易于排查bug。
  • 多次对数据包进行运行将容易推导出相应的内容,密钥固定,客户端被反编译出密钥,将面临破解。

3. 动态密钥加密。

  • 算法逻辑是,在建立连接时,服务器端利用rsa私钥加密一个随机的密钥key,客户端利用rsa公钥解出从服务器端发出的密钥key。至此,在建立连接之后,双方同步了随机的key。
  • 在通信阶段,客户端和服务器端利用握手过程中同步的key,进行des对称加密传输。这个时间段利用des主要考虑效率因素,测试阶段发现rsa的加密解密per都消耗了1k微妙,des则在10微妙左右。
  • 连接终止,双方销毁密钥key。在下一个连接建立时,重新利用rsa同步新的随机密钥key。

该算法比较特殊的地方,在于建立连接的时候,双方利用rsa算法同步了一个随机的密钥,这使得每次通信的加密密钥都是新的。对于外挂的防范:
  • c端和s端连接已经建立的情况下,若中间人拦截数据包,由于此前并没有获得des的密钥key,所以需进行破解,但是破解的时间被限定在了连接终止之前。在短时间内破解出des算法的密钥,几率很小。
  • 如果攻击者反编译出客户端的rsa公钥,想破解出服务端的rsa私钥,用以建立私服,那在技术上是不可行的。
  • 如果已获取了客户端的rsa公钥,想要利用和服务端建立连接的时机,获取通讯时的des密钥key,那是没有意义的,因为每次建立连接,des密钥key都被重新生成。
动态密钥的方法安全性较高,技术实现比其他前两种繁琐,而且涉及到动态的密钥,对bug的追踪构成一定困难。
效率问题存在两个阶段
  • 建立连接的过程中,由rsa同步c和s双方的des密钥,rsa算法相对耗时,对建立连接时的握手有一定影响。
  • 在通信的过程中,由于双方的加解密是利用des对称算法,时间消耗与des算法相关,而des算法的ecb方式每次只能对一组数据(8位加密),cbc方式不限定加密数据长度。经测算,des的cbc方式单个执行都在10微秒左右。高数据量通信有待进一步测试。

client:

#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h> 
#include <errno.h>
#include <sys/time.h>

#include <openssl/des.h>


int main(int argc, char **argv)
{
	if (argc < 3) {
		printf("client <IP> <PORT>\n");
		return 0;
	}

	char str[1024] = {0};
	char buf[1024] = {0};

	int  sd;
	struct sockaddr_in sdaddr;
	
	sd = socket(AF_INET, SOCK_STREAM, 0);
	sdaddr.sin_family = AF_INET;
	inet_pton(AF_INET, argv[1], &sdaddr.sin_addr);
	sdaddr.sin_port = atoi(argv[2]);
	
	int res = connect(sd, (struct sockaddr *)&sdaddr, sizeof(sdaddr));
	printf("res: %d, errno: %d, %s\n", res, errno, strerror(errno));


	////
	unsigned char rbuf[256] = {0};
	res = recv(sd, rbuf, sizeof(rbuf), 0);
	int len = strlen(rbuf);
	for (int i = 0; i < len; ++i)
    	printf("%02X", rbuf[i]);
    printf("\nlen:%d\n", len);

    ////
    DES_cblock key;
    memcpy(&key, rbuf, sizeof(key));
    int ylen = sizeof(key);
    for (int i = 0; i < ylen; ++i)
    	printf("%02X", key[i]);
    printf("\nylen:%d\n", ylen);

    DES_key_schedule key_schedule;
    if (DES_set_key_checked(&key, &key_schedule) != 0) {
          printf("convert to key_schedule failed.\n");
          return -1;
    }

    //IV
    DES_cblock ivec;

	while(1)
	{

		//IV设置为0x0000000000000000
      	memset((char*)&ivec, 0, sizeof(ivec));

		bzero(str, sizeof(str));
		printf("input:");
		scanf("%s\n", str);

		size_t len = (strlen(str)+7)/8 * 8;
		unsigned char *output = malloc(len+1);
		DES_ncbc_encrypt((unsigned char*)str, output, strlen(str), &key_schedule, &ivec, DES_ENCRYPT);
		int outlen = strlen(output);
		printf("output:");
		for (int i = 0; i < outlen; ++i)
    		printf("%02X", output[i]);
    	printf("\noutlen:%d\n", outlen);


		send(sd, output, strlen(output), 0);
		free(output);
		

		////////////
		bzero(buf, sizeof(buf));
		res = recv(sd, buf, sizeof(buf), 0);
		//printf("res: %d\n", res);
		
		printf("recv: %s\n", buf);
		
	}
	return 0;
}


server

#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h> 
#include <sys/epoll.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/time.h>

#include <openssl/des.h>

#define EVENTS_NOMBER 1024


struct recv
{
	char header[256];
	char data[1024];
	
	char recvbuf[1024];
	char sendbuf[1024];
	
	int sockedfd;
	int retfd;
};

struct sock_operations
{
	int (*get_sockfd)(const char *domain, int port);
	int (*setNoneBlocking)(int fd);
	void (*add_eventfd)(int epollfd, int fd);
	void (*pth_work)(pthread_t *pid,void *fd);
	DES_cblock key;
	
};

struct  Recv_sock
{
	struct recv recvdata;
	struct sock_operations operations;
};


int setNoneBlocking(int fd)
{
	int old = fcntl(fd, F_GETFL);
	int new = old|O_NONBLOCK;
	fcntl(fd, F_SETFL, new);
	return old;
}

void addfd(int epollfd, int fd)
{
	struct epoll_event event;
	event.data.fd = fd;
	event.events = EPOLLIN;
	epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);
	setNoneBlocking(fd);
}

void *work(void *recv_sock_addr)
{
	struct Recv_sock *recv_sock = (struct Recv_sock *) recv_sock_addr;
	int retfd = recv_sock->recvdata.retfd;
	
	bzero(recv_sock->recvdata.recvbuf, sizeof(recv_sock->recvdata.recvbuf));
	bzero(recv_sock->recvdata.sendbuf, sizeof(recv_sock->recvdata.sendbuf));

	DES_cblock key;
	memcpy(&key, &(recv_sock->operations.key), sizeof(key));
	int ylen = sizeof(key);
	/*
	printf("key:");
    for (int i = 0; i < ylen; ++i)
    	printf("%02X", key[i]);
    printf("\nylen:%d\n", ylen);
    */

	DES_key_schedule key_schedule;
	if (DES_set_key_checked(&key, &key_schedule) != 0) {
          printf("convert to key_schedule failed.\n");
          return;
	}
	DES_cblock ivec;
	memset((char*)&ivec, 0, sizeof(ivec));

	
	int len = recv(retfd, recv_sock->recvdata.recvbuf, sizeof(recv_sock->recvdata.recvbuf), 0);
	int rcblen = strlen(recv_sock->recvdata.recvbuf);
	unsigned char* recvbuf = (unsigned char*) recv_sock->recvdata.recvbuf;
	printf("encrypto:");
	for(int i=0; i<rcblen; ++i) {
		printf("%02X ", recvbuf[i]);
	}
	printf("\nrcblen:%d\n", rcblen);

	char output[1024] = {0};
	DES_ncbc_encrypt((unsigned char*)recv_sock->recvdata.recvbuf, (unsigned char*)output, rcblen, &key_schedule, &ivec, 0);

	printf("recvbuf: %s\n\n", output);
	
	sprintf(recv_sock->recvdata.sendbuf, "len: %d, data:%s\n", len, output);
	send(retfd, recv_sock->recvdata.sendbuf, strlen(recv_sock->recvdata.sendbuf), 0);
}

void pth_work(pthread_t *pid,void *recv_sock)
{
	pthread_create(pid, NULL, work, recv_sock);
}

int get_sockfd(const char *domain, int port)
{
	int sd;
	struct sockaddr_in addr;
	
	sd = socket(AF_INET, SOCK_STREAM, 0);
	bzero(&addr, sizeof(addr));
	addr.sin_family = AF_INET;
	const char *ip = domain;
	inet_pton(AF_INET, ip, &addr.sin_addr);
	addr.sin_port = port;	
	int res = bind(sd, (struct sockaddr *)&addr, sizeof(addr));
	
	sd = res>=0?sd:-1;
	
	return sd;
	
}

struct sock_operations  operations = 
{
	.get_sockfd =  get_sockfd,
	.setNoneBlocking = setNoneBlocking,
	.add_eventfd = addfd,
	.pth_work = pth_work
};

struct  Recv_sock * init(void)
{
	struct  Recv_sock *recv_sock = (struct Recv_sock *) malloc (sizeof(struct Recv_sock));
	recv_sock->operations = operations;
	
	return recv_sock=recv_sock==NULL?NULL:recv_sock;
}

int main(int argc, char **argv)
{
	if (argc < 3) {
		printf("server <IP> <PORT>\n");
		return 0;
	}


	struct Recv_sock *recv_sock = init();
	
	recv_sock->recvdata.sockedfd = recv_sock->operations.get_sockfd(argv[1], atoi(argv[2]));
	
	printf("sd: %d\n", recv_sock->recvdata.sockedfd);
	
	listen(recv_sock->recvdata.sockedfd, 5);
	
	struct epoll_event events[EVENTS_NOMBER];
	int epollfd = epoll_create(5);
	
	recv_sock->operations.add_eventfd(epollfd, recv_sock->recvdata.sockedfd);

	pthread_t pid;	
	while(1)
	{
		
		int ret = epoll_wait(epollfd, events, EVENTS_NOMBER, -1);
		int i;
		for(i=0;i<ret; i++)
		{
			recv_sock->recvdata.retfd = events[i].data.fd;
			
			if(recv_sock->recvdata.retfd==recv_sock->recvdata.sockedfd)
			{
				struct sockaddr_in client_address;
				socklen_t client_addrlength = sizeof(client_address);
				int connfd = accept(recv_sock->recvdata.sockedfd, (struct sockaddr*)&client_address, &client_addrlength);
				recv_sock->operations.add_eventfd(epollfd, connfd);

				///////
				DES_cblock key;
			    DES_random_key(&key);
			    int len = strlen(key);
			    for (int i = 0; i < len; ++i)
         			printf("%02X", key[i]);
      			printf("\nlen:%d\n", len);


				send(connfd, (char*)key, sizeof(key), 0);

				///////
				memcpy(&(recv_sock->operations.key), &key, sizeof(key));
			}
			else if(events[i].events == EPOLLIN)
			{
				recv_sock->operations.pth_work(&pid,recv_sock);
				pthread_join(pid, NULL);
			}
			else
			{
				//printf("something happen...\n");
			}
		}
		
		
	}
	
	
	return 0;
}


对于移动端的openssl来说:

猜你喜欢

转载自blog.csdn.net/adofsauron/article/details/56278455