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

使用libsodium的crypto_secretbox解密后文件末尾出现异常字符求助

问题:解密后文件末尾出现冗余[NUL]字符

我编写了encryptf和decryptf两个函数(后缀加f避免与libsodium原有函数重名),用于通过指定密钥对内容进行加密解密,密钥为随机生成的ANSI字符串。

加密函数实现

int encryptf(const char *input_file, const char *output_file, const unsigned char *key) {  
    if (sodium_init() < 0) {  
        printf("Error initializing\n");  
        return 1;  
    }  
  
    // 打开输入输出文件,确保可读写,不存在则创建
    FILE *input = fopen(input_file, "r");  
    FILE *output = fopen(output_file, "ab+");  
    if (!input || !output) {  
        printf("Error opening files to encrypt\n");  
        return 1;  
    }  
  
    // 获取文件大小
    fseek(input, 0, SEEK_END);  
    size_t file_size = ftell(input);  
    fseek(input, 0, SEEK_SET);  
  
    // 分配明文和密文内存
    unsigned char *plaintext = (unsigned char *) malloc(file_size);  
    unsigned char *ciphertext = (unsigned char *) malloc(file_size + crypto_secretbox_MACBYTES);  
  
    // 创建随机nonce(使用libsodium安全随机函数)
    unsigned char nonce[crypto_secretbox_NONCEBYTES];  
    randombytes(nonce, sizeof(nonce));  
  
    // 读取明文
    fread(plaintext, 1, file_size, input);  
  
    // 此处mac数组未实际使用,可删除
    unsigned char mac[crypto_secretbox_NONCEBYTES];  
  
    // 加密明文
    crypto_secretbox_easy(ciphertext, plaintext, file_size, nonce, key);  
  
    // 写入nonce和密文到输出文件
    fwrite(nonce, 1, sizeof(nonce), output);  
    fwrite(ciphertext, 1, file_size + crypto_secretbox_MACBYTES, output);  
  
    // 清理资源
    fclose(input);  
    fclose(output);  
    free(plaintext);  
    free(ciphertext);  
  
    return 0;  
}

解密函数实现

int decryptf(const char *input_file, const char *output_file, const unsigned char *key) {  
    if (sodium_init() < 0) {  
        printf("Error initializing Libsodium\n");  
        return 1;  
    }  
  
    FILE *input = fopen(input_file, "rb");  
    FILE *output = fopen(output_file, "wb");  
    if (!input || !output) {  
        printf("Error opening files to decrypt\n");  
        return 1;  
    }  
  
    // 读取nonce
    unsigned char nonce[crypto_secretbox_NONCEBYTES];  
    fread(nonce, 1, sizeof(nonce), input);  
  
    // 获取去掉nonce后的文件大小
    fseek(input, 0, SEEK_END);  
    size_t file_size = ftell(input) - crypto_secretbox_NONCEBYTES;  
    fseek(input, crypto_secretbox_NONCEBYTES, SEEK_SET);  
  
    // 分配密文和明文内存
    unsigned char *ciphertext = (unsigned char *) malloc(file_size);  
    unsigned char *plaintext = (unsigned char *) malloc(file_size);  
  
    // 读取密文
    fread(ciphertext, 1, file_size, input);  
  
    // 解密密文
    if (crypto_secretbox_open_easy(plaintext, ciphertext, file_size, nonce, key) != 0) {  
        printf("Error decrypting %s\n", input_file);  
        return 1;  
    }  
  
    // 写入明文到输出文件
    fwrite(plaintext, 1, file_size, output);  
  
    // 清理资源
    fclose(input);  
    fclose(output);  
    free(ciphertext);  
    free(plaintext);  
  
    return 0;  
}

调用示例(参考)

int main(void) {
    FILE *f1 = fopen("tests/file.txt", "ab+");  
  
    if (!f1) {  
        printf("Failed create test files.\n");  
        exit(EXIT_SUCCESS);  
    }  
    fprintf(f1, "HELLO\n\nworld!\n..\n\thello\n../14hf\n1");  
    fclose(f1); 

    char *key = rand_string(32);
    encryptf("tests/file.txt", "tests/file_enc.txt", key);
    printf("File encrypted.\n");

    decryptf("tests/file_enc.txt", "tests/file.txt", key);
}

问题现象

解密后文件内容可正常还原,但末尾会出现无法显示的[NUL]字符。尝试手动移除libsodium的认证标签会导致解密失败,运行环境为搭载M2芯片的2023款MacBook Pro,需要解决冗余字符问题。


解决思路

核心原因

解密时错误地将**密文总长度(含MAC标签)**当作明文长度写入文件。crypto_secretbox_open_easy解密后,明文实际长度为密文长度 - crypto_secretbox_MACBYTES,当前直接把密文长度(含MAC)作为明文长度写入,导致末尾多出crypto_secretbox_MACBYTES个NUL字符。

修复步骤

1. 修正解密函数的明文写入逻辑

在解密函数中,替换原明文写入代码,计算正确的明文长度:

// 替换原fwrite行
size_t plaintext_size = file_size - crypto_secretbox_MACBYTES;
if (plaintext_size > 0) {
    fwrite(plaintext, 1, plaintext_size, output);
}

2. 额外优化建议

  • 加密时打开输入文件用"rb"(二进制模式),避免Windows下换行符转换导致文件大小计算错误;输出文件用"wb"代替"ab+",防止重复写入。
  • 删除加密函数中未使用的mac数组,减少冗余代码。
  • 修正调用示例中的笔误:fkey改为key。

内容的提问来源于stack exchange,提问作者thou mother

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 17:51:01