You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 22:37:29