C++ Socket实现传文件和加密通讯

C++ Socket实现传文件和加密通讯

若socket服务器端和客户端在同内网下,只能在局域网与服务器端连接,如要实现其连接
  1. 租一台服务器直接在服务器运行代码。

  2. 在主机是用内网穿透把服务器的ip映射到外网。

实现和原理如下

1. 包含头文件和库

1
2
3
4
5
6
#include<bits/stdc++.h>
#include<winsock2.h>
#include<gmp.h>

using namespace std;
#pragma comment(lib,"ws2_32.lib")
  • #include<bits/stdc++.h>:包含了几乎所有的标准库。
  • #include<winsock2.h>:用于Windows的网络编程。
  • #include<gmp.h>:GNU多精度算术库,用于大数运算。
  • #pragma comment(lib,"ws2_32.lib"):链接Winsock库。

2. 定义结构体和函数

1
2
3
4
5
struct get_key {
char * n;
char * d;
int e;
};
  • 定义一个结构体get_key,用于存储RSA密钥对的nde

2.1 生成RSA密钥对的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
mpz_t * RSA_por_max_futioin() {
mpz_t key_q, key_p;
mpz_init(key_p);
mpz_init(key_q);
gmp_randstate_t sum;
gmp_randinit_default(sum);
gmp_randseed_ui(sum, time(NULL));
mpz_urandomb(key_p, sum, 2048);
mpz_urandomb(key_q, sum, 2048);
mpz_t *ans = new mpz_t[2];
mpz_init(ans[0]);
mpz_init(ans[1]);
mpz_nextprime(ans[0], key_p);
mpz_nextprime(ans[1], key_q);
mpz_clear(key_q);
mpz_clear(key_p);
return ans;
}
  • 生成两个大素数pq,用于RSA加密。

2.2 获取RSA密钥对的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
get_key* get_key_n() {
mpz_t *primes = RSA_por_max_futioin();
mpz_t key_n, key_e, key_n1;
mpz_t key_d;
mpz_init(key_n);
mpz_init(key_n1);
mpz_init(key_d);
mpz_init_set_ui(key_e, 65537);
mpz_mul(key_n, primes[0], primes[1]);
mpz_sub_ui(primes[0], primes[0], 1);
mpz_sub_ui(primes[1], primes[1], 1);
mpz_mul(key_n1, primes[0], primes[1]);
mpz_invert(key_d, key_e, key_n1);
get_key* ans = new get_key;
char *key_rsa_n = new char[4096];
char *key_rsa_d = new char[4096];
mpz_get_str(key_rsa_n, 10, key_n);
ans->n = key_rsa_n;
mpz_get_str(key_rsa_d, 10, key_d);
ans->d = key_rsa_d;
ans->e = 65537;
mpz_clear(key_n);
mpz_clear(key_d);
mpz_clear(key_n1);
mpz_clear(key_e);
mpz_clear(primes[0]);
mpz_clear(primes[1]);
delete[] primes;
return ans;
}
  • 生成RSA密钥对,包括公钥ne,私钥d

2.3 RSA解密函数

1
2
3
4
5
6
7
8
9
10
11
char *RSA_de(const char *text_c, const char *key_n, const char* key_d) {
mpz_t m, c, n, d;
mpz_init_set_str(c, text_c, 10);
mpz_init_set_str(n, key_n, 10);
mpz_init_set_str(d, key_d, 10);
mpz_init(m);
mpz_powm(m, c, d, n);
char *ans = new char[4096];
mpz_get_str(ans, 10, m);
return ans;
}
  • 使用私钥d和模数n对密文c进行解密,得到明文m

3. 字符转换函数

1
2
3
4
5
6
7
8
9
int transformation(char a[]) {
char c;
for (int i = 0; i <= strlen(a); i++) {
if (97 <= a[i] <= 122) {
c = a[i];
a[i] = c;
}
}
}
  • 将字符数组中的小写字母转换为大写字母。

4. 主函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
int main() {
get_key *key = get_key_n();
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
SOCKET hServSock = socket(PF_INET, SOCK_STREAM, 0);//Ipv4 TCP
SOCKADDR_IN servAddr;//IP地址
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
servAddr.sin_port = htons(1145);//端口号
bind(hServSock, (SOCKADDR*)&servAddr, sizeof(servAddr));//获得本机IP与hServSock绑定
listen(hServSock, 5);//监听函数
SOCKADDR_IN acceptAddr;//对方IP
int acceptAddr_size;
acceptAddr_size = sizeof(acceptAddr);
SOCKET hacceptSock = accept(hServSock, (SOCKADDR*)&acceptAddr, &acceptAddr_size);
printf("对方IP为: %s\n", inet_ntoa(acceptAddr.sin_addr));
char RSA_n[2058];
strcpy(RSA_n, key->n);
send(hacceptSock, RSA_n, 2058, 0);
key->n = RSA_n;
cout << "公钥为" << endl;
cout << key->n << endl;
while (1) {
char message[2058];
char type[16] = {0};
recv(hacceptSock, type, 16, 0);
cout << type << endl;
char type_temporary;
type_temporary = type[0];
cout << type_temporary;
if (type_temporary == '1') {
char transformation_C[2058];
recv(hacceptSock, message, 2048, 0);
cout << "收到消息" << endl;
char *C_mi = RSA_de(message, key->n, key->d);
cout << C_mi << endl;
}
if (type_temporary == '2') {
char filename[2058];
char filename_data[2058];
}
}
}
  • 初始化RSA密钥对。
  • 初始化Winsock库。
  • 创建服务器套接字并绑定到指定端口。
  • 监听客户端连接并接受连接请求。
  • 发送公钥给客户端。
  • 接收并处理客户端发送的消息,根据消息类型进行相应的处理。

来自烤串