C语言实现bvernan(Vernam密码变体)文件加密程序的代码审查与优化需求
嘿,我仔细审阅了你的bvernan文件加密程序代码,发现了几处和算法逻辑不符的问题,还有不少可以提升健壮性和可读性的优化点,下面给你逐一说明:
问题排查
- 核心算法逻辑偏差:按照你描述的bvernan算法,每个块Dj的第i个字节应该和密钥中索引为
(j+i) mod k的字节异或(j是块序号),但你的encodeDivision函数直接用key->buffer[i]和块字节异或,完全没有跟踪块序号j。这会导致所有块都重复使用密钥的前N个字节(N为当前块长度),和预期的算法逻辑完全不符,加密/解密结果会错误。 - 缓冲区变量混淆:在
readF函数里,你把file->bufferLenght(拼写错误,应为length)覆盖成了实际读取的字节数,但这个变量原本是用来存储缓冲区的总大小(即密钥长度)。虽然最后一个块处理时暂时没问题,但变量名的歧义很容易引发后续逻辑错误,也不符合代码可读性要求。 - 错误处理严重缺失:
openKey中如果密钥文件打开失败(比如文件不存在),fopen返回NULL,后续调用keySize会直接触发空指针访问崩溃;openFile如果打开输入/输出文件失败返回NULL,但main函数里直接用这个NULL指针调用encode,会导致空指针解引用;malloc、fread、fwrite都没有检查返回值,内存分配失败、磁盘读取错误、磁盘满等场景下,程序会静默失败甚至崩溃;
- 变量拼写错误:代码中多处把
length写成了lenght,比如Key_t的lenght成员、Register_t的bufferLenght,这种拼写错误会增加代码维护的成本,也容易引发潜在的编译问题。
优化建议
- 修正算法逻辑,跟踪块序号:在
encode函数中维护一个块计数器,每次处理块时,计算每个字节对应的密钥索引为(block_idx + i) % key->length,确保符合bvernan算法的要求。 - 拆分缓冲区变量:把
Register_t中的bufferLenght拆分为buffer_size(存储缓冲区总大小,即密钥长度)和current_read(存储当前实际读取的字节数),彻底避免变量混淆。 - 完善全链路错误处理:
- 所有
fopen、malloc调用后立即检查返回值,失败时打印明确的错误信息(可以用perror)并合理清理资源后退出; - 检查
fread和fwrite的返回值,确保读写的字节数和预期一致,不一致时抛出错误;
- 所有
- 添加头文件保护:所有自定义头文件都添加头文件保护(
#ifndef ... #define ... #endif),防止重复包含引发编译错误。 - 用const修饰只读变量:对于函数中不会修改的参数(比如密钥指针、文件路径),用
const修饰,提升代码安全性和可读性。 - 增强资源清理的健壮性:比如
openFile中如果打开输出文件失败,要先关闭已经打开的输入文件,释放已分配的缓冲区内存,再返回NULL,避免资源泄漏。
修正后的核心代码示例
修正后的encode.c
#include "encode.h" #include <stdio.h> #include <errno.h> #include <string.h> int encode(Register_t* file, const Key_t* key) { if (!file || !key) { fprintf(stderr, "Error: Invalid input pointer\n"); return -1; } long block_idx = 0; // 跟踪当前处理的块序号 int read_bytes; while ((read_bytes = readF(file)) > 0) { encodeDivision(file->buffer, read_bytes, key, block_idx); int write_bytes = writeF(file); if (write_bytes != read_bytes) { fprintf(stderr, "Error: Failed to write all bytes. Written: %d, Expected: %d\n", write_bytes, read_bytes); return -1; } block_idx++; } if (ferror(file->fdIn)) { fprintf(stderr, "Error reading input file: %s\n", strerror(errno)); return -1; } return 0; } void encodeDivision(unsigned char* block, int length, const Key_t* key, long block_idx) { for (int i = 0; i < length; i++) { int key_idx = (block_idx + i) % key->length; block[i] ^= key->buffer[key_idx]; } }
修正后的register.h(拆分变量+拼写修正)
#ifndef REGISTER_H #define REGISTER_H #include <stdio.h> typedef struct Register { unsigned char *buffer; FILE *fdIn; FILE *fdOut; long buffer_size; // 缓冲区总大小(密钥长度) int current_read; // 当前读取的字节数 } Register_t; Register_t *openFile(const char *inPath, const char *outPath, long buffer_size); int readF(Register_t *file); int writeF(Register_t *file); void closeRegister(Register_t *file); #endif // REGISTER_H
修正后的register.c(对应变量调整+错误处理)
#include "register.h" #include <stdlib.h> #include <errno.h> #include <stdio.h> #include <string.h> Register_t* openFile(const char* inPath, const char* outPath, long buffer_size){ Register_t* file = malloc(sizeof(Register_t)); if (!file) { fprintf(stderr, "Error: Failed to allocate memory for Register_t: %s\n", strerror(errno)); return NULL; } file->buffer = malloc(buffer_size); if (!file->buffer) { fprintf(stderr, "Error: Failed to allocate memory for buffer: %s\n", strerror(errno)); free(file); return NULL; } file->buffer_size = buffer_size; file->fdIn = fopen(inPath, "rb"); if (!file->fdIn) { fprintf(stderr, "Error: Failed to open input file %s: %s\n", inPath, strerror(errno)); free(file->buffer); free(file); return NULL; } file->fdOut = fopen(outPath, "wb"); if (!file->fdOut) { fprintf(stderr, "Error: Failed to open output file %s: %s\n", outPath, strerror(errno)); fclose(file->fdIn); free(file->buffer); free(file); return NULL; } return file; } int readF(Register_t* file){ if (!file) return -1; int readbyte = fread(file->buffer, 1, file->buffer_size, file->fdIn); file->current_read = readbyte; return readbyte; } int writeF(Register_t* file){ if (!file) return -1; int writebyte = fwrite(file->buffer, 1, file->current_read, file->fdOut); return writebyte; } void closeRegister(Register_t* file){ if (!file) return; free(file->buffer); fclose(file->fdIn); fclose(file->fdOut); free(file); }
内容的提问来源于stack exchange,提问作者Somakun
相关产品推荐
相关产品推荐

