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

使用Libsodium的secretbox_open_easy无法解密加密文件内容求助

Libsodium secretbox_open_easy解密失败排查方案

首先明确:secretbox_open_easy的返回值不对应标准errno,perror是基于全局errno变量输出信息的,当该函数返回非0但未修改errno时,perror就会显示“Success”——这个提示没有实际参考价值,别被它误导。

接下来重点排查secretbox_open_easy的参数及相关流程:

  • 密文长度必须准确:Libsodium的secretbox密文长度是「明文长度 + crypto_secretbox_MACBYTES」,解密时传入的密文长度必须严格等于这个值。如果加密后保存文件时只存了加密内容、漏掉了末尾的MAC校验块,解密时长度不足必然失败。

  • Nonce必须完全一致:确保解密用的nonce和加密时的二进制字节完全相同,注意nonce长度是crypto_secretbox_NONCEBYTES,别出现以下错误:把二进制nonce当作文本字符串存储/读取导致截断、编码转换错误、读取时字节序不一致。

  • 密钥生成参数完全匹配:虽然你用了相同密码和盐,但要核对crypto_pwhash的所有参数:

    • 哈希算法(比如crypto_pwhash_ALG_DEFAULT)
    • 内存限制(crypto_pwhash_MEMLIMIT_INTERACTIVE等常量)
    • 操作次数(crypto_pwhash_OPSLIMIT_INTERACTIVE等常量)
    • 生成的密钥长度必须是crypto_secretbox_KEYBYTES,盐的长度必须是crypto_pwhash_SALTBYTES
      任何一项和加密时不一致,都会生成不同的密钥,导致解密失败。
  • 输出缓冲区大小足够:解密的明文缓冲区大小必须至少是「密文长度 - crypto_secretbox_MACBYTES」,如果缓冲区过小,可能触发函数返回失败甚至内存溢出。

  • 参数顺序不能搞混:secretbox_open_easy的参数顺序是:

    int crypto_secretbox_open_easy(unsigned char *m, const unsigned char *c, 
                                   unsigned long long clen, const unsigned char *n, 
                                   const unsigned char *k);
    

    依次是明文缓冲区、密文、密文长度、nonce、密钥,别把明文和密文缓冲区搞反,或者nonce与密钥的顺序颠倒。

关键代码对比示例

加密流程关键片段

#define PLAINTEXT_LEN 1024
unsigned char plaintext[PLAINTEXT_LEN] = "待加密内容";
unsigned char ciphertext[PLAINTEXT_LEN + crypto_secretbox_MACBYTES];
unsigned char nonce[crypto_secretbox_NONCEBYTES];
unsigned char key[crypto_secretbox_KEYBYTES];
unsigned char salt[crypto_pwhash_SALTBYTES];

// 生成随机盐和nonce(加密时做一次,然后和密文一起保存)
randombytes_buf(salt, sizeof(salt));
randombytes_buf(nonce, sizeof(nonce));

// 从密码生成密钥
crypto_pwhash(key, sizeof(key), "你的密码", strlen("你的密码"),
              salt, crypto_pwhash_OPSLIMIT_INTERACTIVE,
              crypto_pwhash_MEMLIMIT_INTERACTIVE, crypto_pwhash_ALG_DEFAULT);

// 执行加密
crypto_secretbox_easy(ciphertext, plaintext, PLAINTEXT_LEN, nonce, key);

// 将salt、nonce、ciphertext写入文件(注意写入完整的ciphertext,包括MAC)

解密流程关键片段

// 从文件读取salt、nonce、ciphertext
unsigned char salt[crypto_pwhash_SALTBYTES];
unsigned char nonce[crypto_secretbox_NONCEBYTES];
// 假设读取到的密文长度是CIPHERTEXT_LEN = PLAINTEXT_LEN + crypto_secretbox_MACBYTES
unsigned char ciphertext[CIPHERTEXT_LEN];
unsigned char key[crypto_secretbox_KEYBYTES];
// 明文缓冲区大小 = CIPHERTEXT_LEN - crypto_secretbox_MACBYTES
unsigned char plaintext[CIPHERTEXT_LEN - crypto_secretbox_MACBYTES];

// 用相同参数生成密钥
crypto_pwhash(key, sizeof(key), "你的密码", strlen("你的密码"),
              salt, crypto_pwhash_OPSLIMIT_INTERACTIVE,
              crypto_pwhash_MEMLIMIT_INTERACTIVE, crypto_pwhash_ALG_DEFAULT);

// 执行解密
int ret = crypto_secretbox_open_easy(plaintext, ciphertext, CIPHERTEXT_LEN, nonce, key);
if (ret != 0) {
    // 直接判断返回值,非0即认证失败(密钥/nonce错误、密文篡改等)
    fprintf(stderr, "解密失败:密文认证不通过\n");
    return 1;
}

内容的提问来源于stack exchange,提问作者Swan Geon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 23:36:17