// server.c #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define PORT 8001 #define MAX_CLIENTS 5 #define BUFFER_SIZE 1024 // 密钥和偏移量 uint8_t key[SM4_KEY_SIZE]; uint8_t iv[SM4_BLOCK_SIZE]; // 将信号量定义为全局变量 dispatch_semaphore_t semaphore; int log_pipe[2]; // 日志记录的管道 // 生成时间戳目录 void create_timestamp_dir(char *dir_name) { time_t now = time(NULL); struct tm *t = localtime(&now); // t->tm_year:从 1900 年开始的年数,因此需要加上 1900 得到完整的年份。 // t->tm_mon:从 0 开始的月份(0 表示 1 月),因此需要加上 1 得到实际的月份。 // t->tm_mday:月份中的日期。 // t->tm_hour:小时。 // t->tm_min:分钟。 // t->tm_sec:秒。 sprintf(dir_name, "./files/%04d%02d%02d%02d%02d%02d", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); mkdir("./files", 0777); mkdir(dir_name, 0777); // 创建解密结果文件目录 mkdir("./files/decrypt", 0777); } // 记录日志 void log_operation(const char *message) { write(log_pipe[1], message, strlen(message)); } // 文件压缩 int compress_file(const char *src, const char *dest) { FILE *source = fopen(src, "rb"); gzFile dest_file = gzopen(dest, "wb"); if (!source || !dest_file) return -1; char buffer[BUFFER_SIZE]; int bytes_read; while ((bytes_read = fread(buffer, 1, BUFFER_SIZE, source)) > 0) { gzwrite(dest_file, buffer, bytes_read); } fclose(source); gzclose(dest_file); return 0; } // 文件解压 int decompress_file(const char *src, const char *dest) { gzFile source = gzopen(src, "rb"); FILE *dest_file = fopen(dest, "wb"); if (!source || !dest_file) return -1; char buffer[BUFFER_SIZE]; int bytes_read; while ((bytes_read = gzread(source, buffer, BUFFER_SIZE)) > 0) { fwrite(buffer, 1, bytes_read, dest_file); } gzclose(source); fclose(dest_file); return 0; } // 加密文件方法 int sm4_cbc_padding_encrypt_file(const char *input_file, const char *output_file, const uint8_t *key, const uint8_t *iv) { SM4_KEY enc_key; sm4_set_encrypt_key(&enc_key, key); // 设置加密密钥 FILE *in_file = fopen(input_file, "rb"); FILE *out_file = fopen(output_file, "wb"); if (!in_file || !out_file) { perror("文件打开失败"); return 0; } uint8_t input_block[SM4_BLOCK_SIZE]; uint8_t output_block[SM4_BLOCK_SIZE + SM4_BLOCK_SIZE]; // 加密后可能需要填充 size_t bytes_read, outlen; while ((bytes_read = fread(input_block, 1, SM4_BLOCK_SIZE, in_file)) > 0) { if (feof(in_file)) { // 最后一块,带填充加密 if (sm4_cbc_padding_encrypt(&enc_key, iv, input_block, bytes_read, output_block, &outlen) != 1) { fprintf(stderr, "加密失败。\n"); fclose(in_file); fclose(out_file); return 0; } } else { // 中间块,不需要填充 if (sm4_cbc_padding_encrypt(&enc_key, iv, input_block, SM4_BLOCK_SIZE, output_block, &outlen) != 1) { fprintf(stderr, "加密失败。\n"); fclose(in_file); fclose(out_file); return 0; } } fwrite(output_block, 1, outlen, out_file); } fclose(in_file); fclose(out_file); return 1; // 成功 } // 解密文件方法 int sm4_cbc_padding_decrypt_file(const char *input_file, const char *output_file, const uint8_t *key, const uint8_t *iv) { SM4_KEY dec_key; sm4_set_decrypt_key(&dec_key, key); // 设置解密密钥 FILE *in_file = fopen(input_file, "rb"); FILE *out_file = fopen(output_file, "wb"); if (!in_file || !out_file) { perror("文件打开失败"); return 0; } uint8_t input_block[SM4_BLOCK_SIZE + SM4_BLOCK_SIZE]; // 假设有填充 uint8_t output_block[SM4_BLOCK_SIZE]; size_t bytes_read, outlen; while ((bytes_read = fread(input_block, 1, sizeof(input_block), in_file)) > 0) { if (feof(in_file)) { // 最后一块,带填充解密 if (sm4_cbc_padding_decrypt(&dec_key, iv, input_block, bytes_read, output_block, &outlen) != 1) { fprintf(stderr, "带填充解密解密失败。\n"); fclose(in_file); fclose(out_file); return 0; } } else { // 中间块,不需要处理填充 if (sm4_cbc_padding_decrypt(&dec_key, iv, input_block, bytes_read, output_block, &outlen) != 1) { fprintf(stderr, "不需要处理填充解密失败。\n"); fclose(in_file); fclose(out_file); return 0; } } fwrite(output_block, 1, outlen, out_file); } fclose(in_file); fclose(out_file); return 1; // 成功 } void extract_path_and_filename(const char *input, char *path, char *filename) { int last_slash_index = -1; // 记录最后一个 '/' 的位置 int last_dot_index = -1; // 记录最后一个 '.' 的位置 // 遍历路径字符串,找到最后一个 '/' 和 '.' for (int i = 0; input[i] != '\0'; i++) { if (input[i] == '/') { last_slash_index = i; // 更新最后一个 '/' 的位置 } if (input[i] == '.') { last_dot_index = i; // 更新最后一个 '.' 的位置 } } // 提取路径部分(从开头到最后一个 '/') if (last_slash_index != -1) { strncpy(path, input, last_slash_index + 1); path[last_slash_index + 1] = '\0'; // 确保路径部分以 '\0' 结尾 } else { path[0] = '\0'; // 如果没有 '/', 为空 } // 如果 '.' 在 '/' 之前或没有 '.', 忽略后缀处理 if (last_dot_index <= last_slash_index) { last_dot_index = -1; } // 提取文件名部分(从最后一个 '/' 到最后一个 '.' 之间) int j = 0; // 文件名的索引 for (int i = last_slash_index + 1; i < (last_dot_index == -1 ? strlen(input) : last_dot_index); i++) { filename[j++] = input[i]; } filename[j] = '\0'; // 添加字符串结束符 } // 客户端处理线程 void *client_handler(void *arg) { int client_socket = *(int *)arg; free(arg); char buffer[BUFFER_SIZE]; while (1) { printf("等待客户端发送命令中...\n"); // 初始化缓冲区为 0 memset(buffer, 0, BUFFER_SIZE); // 接收第一个参数判断参数客户端需要上传还是下载 int bytes = read(client_socket, buffer, BUFFER_SIZE - 1); // 预留一个字节用于NULL终止符 if (bytes <= 0) { perror("接收客户端命令失败"); break; // 如果读取失败或连接关闭,退出循环 } buffer[bytes] = '\0'; // 确保以 NULL 结尾 char upload_or_download[256]; snprintf(upload_or_download, sizeof(upload_or_download), "%s", buffer); printf("客户端发起请求:%s, 等待后续指令....\n", upload_or_download); char origin_file_path[256], dir_name[128], file_path[256], compressed_file[256], decrypted_file[256]; if (strcmp(upload_or_download, "upload") == 0) { // 接收文件名(不含后缀) int bytes = read(client_socket, buffer, BUFFER_SIZE); if (bytes <= 0) { perror("接收文件名失败"); return NULL; } buffer[bytes] = '\0'; // 确保以 NULL 结尾 char file_name[256]; snprintf(file_name, sizeof(file_name), "%s", buffer); printf("接收文件名:%s\n", file_name); // 发送 ACK 确认 send(client_socket, "ACK", strlen("ACK"), 0); // 先生成./files目录,再生成时间戳目录,调用 create_timestamp_dir 函数,生成一个基于时间戳的目录名称,并将其存储在 dir_name 中 create_timestamp_dir(dir_name); // 根据传入的文件名以及时间戳拼接生成源文件路径 sprintf(origin_file_path, "%s/%s.txt", dir_name, buffer); // 加密后的文件路径 sprintf(file_path, "%s/%s.enc", dir_name, buffer); // 加密后压缩包的文件路径 sprintf(compressed_file, "%s/%s.gz", dir_name, buffer); // 解密的文件路径 snprintf(decrypted_file, sizeof(decrypted_file), "./files/decrypt/%s_decrypted.txt", buffer); printf("源文件路径:%s\n加密后的文件:%s\n压缩的文件:%s\n解密的文件路径:%s\n", origin_file_path, file_path, compressed_file, decrypted_file); FILE *file = fopen(origin_file_path, "w"); if (!file) { perror("文件打开失败"); return NULL; } // 接收分块数据 int bytes_received; while ((bytes_received = recv(client_socket, buffer, BUFFER_SIZE, 0)) > 0) { // 检查是否包含结束标志 if (strstr(buffer, "EOF") != NULL) { fwrite(buffer, 1, bytes_received - strlen("EOF"), file); // 写入实际数据 break; } fwrite(buffer, 1, bytes_received, file); printf("接收到 %d 字节数据。\n", bytes_received); } fclose(file); log_operation("文件已接收。\n"); // 加密文件 printf("正在加密文件...\n"); sm4_cbc_padding_encrypt_file(origin_file_path, file_path, key, iv); printf("文件加密完成。\n"); char log_message_file_path[BUFFER_SIZE]; sprintf(log_message_file_path, "文件已加密。加密文件保存路径为:%s\n", file_path); log_operation(log_message_file_path); // 压缩文件 printf("正在压缩被加密的文件...\n"); compress_file(file_path, compressed_file); printf("文件压缩完成。\n"); // 删除加密文件 // remove(file_path); char log_message_compressed_file[BUFFER_SIZE]; sprintf(log_message_compressed_file, "文件已加密。加密文件保存路径为:%s\n", compressed_file); // 发送压缩的加密文件路径给客户端 send(client_socket, compressed_file, strlen(compressed_file), 0); log_operation(log_message_compressed_file); } else if (strcmp(upload_or_download, "download") == 0) { printf("接收到下载请求...\n"); memset(buffer, 0, BUFFER_SIZE); // 读取文件路径 read(client_socket, buffer, BUFFER_SIZE); char path[256]; // 存储提取的路径(无后缀) char filename[256]; // 存储提取的文件名 extract_path_and_filename(buffer, path, filename); //压缩包路径 sprintf(compressed_file, "%s", buffer); // 解压后的加密文件路径 sprintf(file_path, "./files/decrypt/%s.enc",filename); // 解密文件路径 sprintf(decrypted_file, "./files/decrypt/%s.txt", filename); printf("%s\n", compressed_file); printf("%s\n", file_path); printf("%s\n", decrypted_file); // 解压缩、解密并发送给客户端 decompress_file(compressed_file, file_path); printf("文件解压缩完成。\n"); printf("正在解密文件...\n"); sm4_cbc_padding_decrypt_file(file_path, decrypted_file, key, iv); printf("文件解密完成。\n"); log_operation("文件已解压并解密,准备发送。\n"); // 向客户端发送 "READY" 信号 send(client_socket, "READY", strlen("READY"), 0); // 发送解密后的文件 FILE *file_to_send = fopen(decrypted_file, "rb"); while (!feof(file_to_send)) { int bytes_read = fread(buffer, 1, BUFFER_SIZE, file_to_send); send(client_socket, buffer, bytes_read, 0); } fclose(file_to_send); printf("文件发送完成。\n"); // 向客户端发送 "READY" 信号 send(client_socket, "stop", strlen("stop"), 0); // 删除解密后的文件 // remove(decrypted_file); } else { perror("读取客户端命令失败"); break; } memset(buffer, 0, BUFFER_SIZE); // 清空缓冲区,准备接收下一个命令 } // 关闭连接 close(client_socket); dispatch_semaphore_signal(semaphore); return NULL; } int main() { int server_socket, client_socket; struct sockaddr_in server_addr, client_addr; socklen_t client_addr_len = sizeof(client_addr); // 创建服务器 socket server_socket = socket(AF_INET, SOCK_STREAM, 0); if (server_socket == -1) { perror("服务器 socket 创建失败"); exit(EXIT_FAILURE); } // 设置服务器地址 server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = htons(PORT); // 绑定服务器 socket if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) { perror("绑定失败"); close(server_socket); exit(EXIT_FAILURE); } // 开始监听 if (listen(server_socket, MAX_CLIENTS) == -1) { perror("监听失败"); close(server_socket); exit(EXIT_FAILURE); } // 初始化信号量 semaphore = dispatch_semaphore_create(MAX_CLIENTS); if (semaphore == NULL) { fprintf(stderr, "信号量创建失败\n"); return -1; } // 随机生成加密密钥和 IV if (rand_bytes(key, SM4_KEY_SIZE) != 1) { fprintf(stderr, "随机密钥生成失败。\n"); return -1; } if (rand_bytes(iv, SM4_BLOCK_SIZE) != 1) { fprintf(stderr, "随机IV生成失败。\n"); return -1; } // 打印密钥和 IV printf("随机生成的密钥: "); for (size_t i = 0; i < SM4_KEY_SIZE; i++) { printf("%02X ", key[i]); } printf("\n"); printf("随机生成的IV: "); for (size_t i = 0; i < SM4_BLOCK_SIZE; i++) { printf("%02X ", iv[i]); } printf("\n"); // 示例:客户端处理逻辑 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); // 等待信号量 // printf("客户端进入,当前资源被占用\n"); // 创建管道 pipe(log_pipe); if (fork() == 0) // 日志进程 { close(log_pipe[1]); // 关闭写端 char log_buffer[BUFFER_SIZE]; while (read(log_pipe[0], log_buffer, BUFFER_SIZE) > 0) { printf("日志: %s\n", log_buffer); } exit(0); } printf("服务器已启动,等待客户端连接...\n"); while (1) { dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); // printf("客户端进入,当前资源被占用\n"); int client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_addr_len); if (client_socket == -1) { perror("接受客户端连接失败"); continue; } printf("客户端连接成功,地址: %s\n", inet_ntoa(client_addr.sin_addr)); int *client_sock = malloc(sizeof(int)); *client_sock = client_socket; pthread_t thread_id; pthread_create(&thread_id, NULL, client_handler, client_sock); pthread_detach(thread_id); } close(server_socket); // 释放信号量 dispatch_release(semaphore); return 0; }