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

C语言libsodium输出与PHP集成困难排查求助

问题诊断与修复方案

看起来你碰到的问题是C程序生成的密封密钥数据格式不对,导致PHP的sodium_crypto_box_seal_open()解析失败返回null。既然你已经确认PHP逻辑没问题,那问题肯定出在C代码的输出上。我仔细检查了你的代码,发现两个关键的长度处理错误,这应该就是根源所在:

1. 写入密封密钥时的长度错误

在// Seal Key部分,你用sizeof sealed来写入文件,但sealed是指针类型,sizeof sealed返回的是指针本身的字节数(比如64位系统上是8字节),而不是实际的密封数据总长度。正确的长度应该是crypto_box_SEALBYTES + crypto_secretstream_xchacha20poly1305_KEYBYTES,也就是密封后的密钥总字节数。

错误代码:

fwrite(sealed,1,sizeof sealed,fp_o);

修复后:

const size_t sealed_len = crypto_box_SEALBYTES + crypto_secretstream_xchacha20poly1305_KEYBYTES;
fwrite(sealed, 1, sealed_len, fp_o);

2. Base64解码公钥时的缓冲区大小错误

解析输入公钥的Base64时,你给sodium_base642bin传的第二个参数是sizeof(inputKeyBin),但inputKeyBin是指针,这个值同样是指针的大小,而非实际需要的公钥字节数crypto_box_PUBLICKEYBYTES。这会导致解码缓冲区不足,要么解析出错误的公钥,要么直接破坏内存,最终生成无效的密封数据。

错误代码:

if (sodium_base642bin(inputKeyBin,sizeof(inputKeyBin),inputKey,strlen(inputKey),NULL,&bin_len,&b64_end,sodium_base64_VARIANT_ORIGINAL) !=0)

修复后:

if (sodium_base642bin(inputKeyBin, crypto_box_PUBLICKEYBYTES, inputKey, strlen(inputKey), NULL, &bin_len, &b64_end, sodium_base64_VARIANT_ORIGINAL) != 0)

额外的内存管理建议(可选但重要)

你用sodium_malloc分配了好几块内存,但没调用sodium_free释放,长期运行可能会导致内存泄漏。建议在程序结束前或者不再使用这些内存时释放:

sodium_free(inputKeyBin);
sodium_free(key);
sodium_free(sealed);
sodium_free(base64Out);
sodium_free(base64OutX);

完整修复后的C代码

我把修复后的完整代码整理好了,你可以直接替换测试:

#include <sodium.h> 
#include "filedata.h" 
#include <stdio.h> 
#include <string.h>

#define CHUNK_SIZE 8192 

void doEncrypt(char * inKey,char * plainText,char * cipherText,char * outKey) { 
    //Get input key 
    //const char *inputKey=readFile(inKey); 
    const char *inputKey="aQFsJJuU65zXKzqDfS1KuxqqebkER/cPqno+oZL5PgQ="; // testing with a fixed value.... 
    unsigned char * inputKeyBin = sodium_malloc(crypto_box_PUBLICKEYBYTES); 
    size_t bin_len; 
    const char *b64_end; 

    // 修复:使用正确的公钥缓冲区大小
    if (sodium_base642bin(inputKeyBin, crypto_box_PUBLICKEYBYTES, inputKey, strlen(inputKey), NULL, &bin_len, &b64_end, sodium_base64_VARIANT_ORIGINAL) !=0) { 
        printf("sodium_base642bin() failure\n"); 
        exit(1); 
    } 

    // Encrypt file START 
    unsigned char *key; 
    unsigned char buf_in[CHUNK_SIZE]; 
    unsigned char buf_out[CHUNK_SIZE+crypto_secretstream_xchacha20poly1305_ABYTES]; 
    unsigned char header[crypto_secretstream_xchacha20poly1305_HEADERBYTES]; 
    crypto_secretstream_xchacha20poly1305_state st; 
    FILE *fp_t,*fp_s; 
    unsigned long long out_len; 
    size_t rlen; 
    int eof; 
    unsigned char tag; 

    key = (unsigned char *)sodium_malloc(crypto_secretstream_xchacha20poly1305_KEYBYTES); 
    crypto_secretstream_xchacha20poly1305_keygen(key); 

    fp_s = fopen(plainText, "rb"); 
    fp_t = fopen(cipherText, "wb"); 

    crypto_secretstream_xchacha20poly1305_init_push(&st, header, key); 
    fwrite(header, 1, sizeof header, fp_t); 

    do { 
        rlen = fread(buf_in, 1, sizeof buf_in, fp_s); 
        eof = feof(fp_s); 
        tag = eof ? crypto_secretstream_xchacha20poly1305_TAG_FINAL : 0; 
        crypto_secretstream_xchacha20poly1305_push(&st, buf_out, &out_len, buf_in, rlen, NULL, 0, tag); 
        fwrite(buf_out, 1, (size_t) out_len, fp_t); 
    } while (! eof); 

    fclose(fp_t); 
    fclose(fp_s); 
    // Encrypt file END 

    // Seal Key 
    const size_t sealed_len = crypto_box_SEALBYTES + crypto_secretstream_xchacha20poly1305_KEYBYTES;
    unsigned char * sealed = sodium_malloc(sealed_len); 

    if (crypto_box_seal(sealed, key, crypto_secretstream_xchacha20poly1305_KEYBYTES, inputKeyBin) !=0) { 
        printf("crypto_box_seal() failure\n"); 
        exit(1); 
    } 

    FILE *fp_o; 
    fp_o = fopen(outKey,"wb"); 
    // 修复:写入正确长度的密封数据
    fwrite(sealed, 1, sealed_len, fp_o); 
    fclose(fp_o); 

    const size_t outSz = sodium_base64_encoded_len(sealed_len, sodium_base64_VARIANT_ORIGINAL); 
    char * base64Out = sodium_malloc(outSz); 
    sodium_bin2base64(base64Out, outSz, sealed, sealed_len, sodium_base64_VARIANT_ORIGINAL); 
    printf("E: %s\n",base64Out); 

    const size_t outSzX = sodium_base64_encoded_len(crypto_secretstream_xchacha20poly1305_KEYBYTES, sodium_base64_VARIANT_ORIGINAL); 
    char * base64OutX = sodium_malloc(outSzX); 
    sodium_bin2base64(base64OutX, outSzX, key, crypto_secretstream_xchacha20poly1305_KEYBYTES, sodium_base64_VARIANT_ORIGINAL); 
    printf("K: %s\n",base64OutX); 

    // 新增:释放所有sodium_malloc分配的内存
    sodium_free(inputKeyBin);
    sodium_free(key);
    sodium_free(sealed);
    sodium_free(base64Out);
    sodium_free(base64OutX);
}

验证步骤

  1. 编译修复后的C程序,运行生成加密文件和密封密钥的Base64输出
  2. 把E: 后面的Base64字符串复制到PHP代码的$sealedDataFromC变量里
  3. 此时PHP的sodium_crypto_box_seal_open()应该能正确解析出密钥,不再返回null了

内容的提问来源于stack exchange,提问作者Little Code

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:03:21