使用openssl BIO逐块进行base64解码

Posted

技术标签:

【中文标题】使用openssl BIO逐块进行base64解码【英文标题】:base64 decode with openssl BIO block by block 【发布时间】:2017-04-21 10:35:40 【问题描述】:

我在使用以下代码解码 base64 编码数据时遇到问题。我有大约 3.5 MB 的数据要解码。它几乎可以正常工作,直到最后缺少某些东西。

以下代码读取 100 kB 源数据块,将其写入 BIO_s_mem,然后多次读取 1024 字节的解码数据。当没有更多内容可读取时,将检索另一个 100 kB 块并再次使用。在收到最后一个块之前一切正常。它没有完整的 100 kB(只有 25685 字节)。我将它写入 BIO,解码 18 次 1024 字节,然后再解码 435 次,仅此而已。但这还不是全部。仍有大约 100 字节的解码数据无法读取。

正确接收所有编码数据(将它们保存到文件并从 shell 命令手动解码可提供完整输出)。我应该如何从 BIO 获得其余部分?我想我应该以某种方式说这就是全部。例如,我尝试了多种方式 BIO_flush,一些标志,在编码数据中添加换行符,但还没有成功。

BIO *bmem, *b64;
b64 = BIO_new(BIO_f_base64());
bmem = BIO_new(BIO_s_mem());
BIO_push(b64, bmem);
vector<char> buf(1024);

while (!end) 
    end = task->nextChunk(chunk, chunkSize); // this reads encoded data block
    BIO_write(bmem, (void*)chunk, chunkSize);
    cout << "Chunk size: " << chunkSize << endl;
    if (end || chunkSize == 0) 
        BIO_flush(bmem); // I tried multiple things
        BIO_flush(b64); // flush here and there, nothing helped
        BIO_set_close(bmem, BIO_CLOSE); // and other things... ;-)
    

    string result;
    int nread;
    while ((nread = BIO_read(b64, buf.data(), buf.size())) > 0) 
        cout << "Decoded bytes read: " << nread << endl;
        result.append(buf.data(), nread);
    
    ret->appendRaw(result.c_str(), result.size()); // store result somehow

最后输出序列:

Chunk size: 25685
Decoded bytes read: 1024
Decoded bytes read: 1024
Decoded bytes read: 1024
Decoded bytes read: 1024
Decoded bytes read: 1024
Decoded bytes read: 1024
Decoded bytes read: 1024
Decoded bytes read: 1024
Decoded bytes read: 1024
Decoded bytes read: 1024
Decoded bytes read: 1024
Decoded bytes read: 1024
Decoded bytes read: 1024
Decoded bytes read: 1024
Decoded bytes read: 1024
Decoded bytes read: 1024
Decoded bytes read: 1024
Decoded bytes read: 1024
Decoded bytes read: 435
Chunk size: 0

再说一次:解码后的输出是二进制文件。它已正确编码,正确发送到我的代码,但未解码,最后大约 100 个字节丢失。 感谢您的任何提示。

【问题讨论】:

认为 (nread = BIO_read(b64, buf.data(), buf.size())) &gt; 0 可能不太正确。我认为对生物执行的测试是do len = BIO_read(b64, ...); while (len &gt; 0 || BIO_should_retry(b64)); 但这是针对套接字生物的;我不确定文件或内存生物有何不同。 感谢您的提示。我已经对此进行了实验。当所有块都写入我的 BIO_s_mem 时,从 b64 读取会给出 -1 并且 BIO_should_retry(b64) 保持为真,因此它永远不会结束。这就是为什么我认为我需要以某种方式说“就是这样”,最后一部分将被解码,返回并且循环可以完成。 【参考方案1】:

诀窍在于在最终的 BIO_read 序列之前添加以下两行:

        BIO_write(bmem, "\n", 1);
        BIO_set_mem_eof_return(bmem, BIO_NOCLOSE);

【讨论】:

以上是关于使用openssl BIO逐块进行base64解码的主要内容,如果未能解决你的问题,请参考以下文章

OpenSSL 使用 base64 编码/解码(liang19890820)

Base64 解码 - 不正确的字符串长度

OpenSSL之EVP用法

openssl pem转cer文件 并用base64编码解码过程

openssl提供 DES_ecb3_encrypt方法

c语言中的openssl aes解密