使用 OpenSSL 进行 Base64 编码和解码
我一直在尝试找出用于 Base64 解码和编码的 openssl 文档。我在下面找到了一些代码片段
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
char *base64(const unsigned char *input, int length)
{
BIO *bmem, *b64;
BUF_MEM *bptr;
b64 = BIO_new(BIO_f_base64());
bmem = BIO_new(BIO_s_mem());
b64 = BIO_push(b64, bmem);
BIO_write(b64, input, length);
BIO_flush(b64);
BIO_get_mem_ptr(b64, &bptr);
char *buff = (char *)malloc(bptr->length);
memcpy(buff, bptr->data, bptr->length-1);
buff[bptr->length-1] = 0;
BIO_free_all(b64);
return buff;
}
char *decode64(unsigned char *input, int length)
{
BIO *b64, *bmem;
char *buffer = (char *)malloc(length);
memset(buffer, 0, length);
b64 = BIO_new(BIO_f_base64());
bmem = BIO_new_mem_buf(input, length);
bmem = BIO_push(b64, bmem);
BIO_read(bmem, buffer, length);
BIO_free_all(bmem);
return buffer;
}
这似乎只适用于单行字符串,例如“Start”,当我引入带有换行符和空格等的复杂字符串时,它会严重失败。
它甚至不必是 openssl,一个简单的类或一组做同样事情的函数就可以了,解决方案有一个非常复杂的构建过程,我试图避免必须进入那里并进行多次更改。我选择 openssl 的唯一原因是因为该解决方案已经使用库进行了编译。
I've been trying to figure out the openssl documentation for base64 decoding and encoding. I found some code snippets below
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
char *base64(const unsigned char *input, int length)
{
BIO *bmem, *b64;
BUF_MEM *bptr;
b64 = BIO_new(BIO_f_base64());
bmem = BIO_new(BIO_s_mem());
b64 = BIO_push(b64, bmem);
BIO_write(b64, input, length);
BIO_flush(b64);
BIO_get_mem_ptr(b64, &bptr);
char *buff = (char *)malloc(bptr->length);
memcpy(buff, bptr->data, bptr->length-1);
buff[bptr->length-1] = 0;
BIO_free_all(b64);
return buff;
}
char *decode64(unsigned char *input, int length)
{
BIO *b64, *bmem;
char *buffer = (char *)malloc(length);
memset(buffer, 0, length);
b64 = BIO_new(BIO_f_base64());
bmem = BIO_new_mem_buf(input, length);
bmem = BIO_push(b64, bmem);
BIO_read(bmem, buffer, length);
BIO_free_all(bmem);
return buffer;
}
This only seems to work for single line strings such as "Start", the moment I introduce complex strings with newlines and spaces etc it fails horribly.
It doesn't even have to be openssl, a simple class or set of functions that do the same thing would be fine, theres a very complicated build process for the solution and I am trying to avoid having to go in there and make multiple changes. The only reason I went for openssl is because the solution is already compiled with the libraries.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
就我个人而言,我发现 OpenSSL API 使用起来非常痛苦,我会避免使用它,除非避免它的成本非常高。我发现它已经成为加密世界的标准 API 非常令人沮丧。
我觉得无聊,我用 C++ 给你写了一个。这个甚至应该处理可能导致安全问题的边缘情况,例如,对一个字符串进行编码,因为它太大而导致整数溢出。
我已经对其进行了一些单元测试,所以它应该可以工作。
Personally, I find the OpenSSL API to be so incredibly painful to use, I avoid it unless the cost of avoiding it is extremely high. I find it quite upsetting that it has become the standard API in the crypto world.
I was feeling bored, and I wrote you one in C++. This one should even handle the edge cases that can cause security problems, like, for example, encoding a string that results in integer overflow because it's too large.
I have done some unit testing on it, so it should work.
使用
EVP_
界面。例如:EVP 功能也包括流接口,请参阅手册页。
Rather than using the
BIO_
interface it's much easier to use theEVP_
interface. For instance:The EVP functions include a streaming interface too, see the man page.
这是我编写的 OpenSSL base64 编码/解码的示例:
注意,我编写的代码中有一些宏/类,但它们对于该示例都不重要。它只是我写的一些 C++ 包装器:
Here is an example of OpenSSL base64 encode/decode I wrote:
Notice, I have some macros/classes in the code that I wrote, but none of them is important for the example. It is simply some C++ wrappers I wrote:
这对我有用,并使用 valgrind 验证没有内存泄漏。
编译:
输出:
This works for me, and verified no memory leaks with valgrind.
Compile:
Output:
这么多带有缓冲区和
malloc()
的可怕C
代码示例,在这个C++std::string
怎么样?代码>标记的问题?So many horrible
C
code examples with buffers andmalloc()
, what about usingstd::string
properly on thisC++
tagged question?我喜欢 mtrw 使用 EVP。
下面是我的“现代 C++”对他的回答的看法,无需手动内存分配(
calloc
)。它需要一个 std::string ,但它可以很容易地重载以使用原始字节。可能有一种更干净/更好的方法来做到这一点(我想摆脱
reinterpret_cast
)。您肯定还需要一个 try/catch 块来处理潜在的异常。I like mtrw's use of EVP.
Below is my "modern C++" take on his answer without manual memory allocation (
calloc
). It will take astd::string
but it can easily be overloaded to use raw bytes for example.There's probably a cleaner/better way of doing this (I'd like to get rid of
reinterpret_cast
). You'll also definitely want atry/catch
block to deal with the potential exception.改进了 TCS 答案以删除宏/数据结构
从文件到文件写入文件
Base64 编码。很多时候,由于文件限制,我们读取数据块并进行编码。下面是代码。
Improved TCS answer to remove macros/datastructures
To write to file
Base64 encoding from file to file. Many times due to file constraint we have read in chunks of data and do encoding. Below is the code.
Base64 确实非常简单;通过快速 Google 搜索,您应该不会遇到任何数量的实现问题。例如,此处是来自 C 语言的参考实现互联网软件联盟,有详细的评论解释了该过程。
openssl 实现通过“BIO”内容增加了很多复杂性,如果您所做的只是解码/编码,那么这些内容(恕我直言)不是很有用。
Base64 is really pretty simple; you shouldn't have trouble finding any number of implementations via a quick Google. For example here is a reference implementation in C from the Internet Software Consortium, with detailed comments explaining the process.
The openssl implementation layers a lot of complexity with the "BIO" stuff that's not (IMHO) very useful if all you're doing is decoding/encoding.
聚会迟到了,但我最近自己也遇到了这个问题,但对 BIO 解决方案不满意,它不必要地复杂,但也不喜欢“EncodeBlock”,因为它引入了我在 Base64 编码中不想要的换行符细绳。
经过一番嗅探后,我发现了头文件
openssl/include/crypto/evp.h
它不是默认安装的一部分(它只为我导出 include/openssl 文件夹),但导出问题的解决方案。使用此功能,使用 EVP 接口就可以实现“无换行符”。
示例:
这段代码将缓冲区编码为 Base64,不带换行符。
请注意使用
EVP_ENCODE_CTX_num
来获取仍然存储在上下文对象中的“剩余字节”,以计算正确的缓冲区大小。仅当您需要多次调用
EVP_EncodeUpdate
时才需要这样做,因为您的数据非常大或无法立即可用。Late to the party, but I came across this problem recently myself, but was unhappy with both the BIO solution, which is unnecessarily convoluted, but did not like 'EncodeBlock' either, because it introduces newline characters I do not want in my Base64 encoded string.
After a little sniffing, I came across the header file
openssl/include/crypto/evp.h
which is not part of the default installation (which only exports the include/openssl folder for me), but exports the solution to the problem.Using this function, the 'no newline' becomes possible using the EVP interface.
Example:
This piece of code will encode the buffer to Base64 without the newlines.
Please note the use of
EVP_ENCODE_CTX_num
to obtain the 'leftover bytes' still stored in the context object to calculate the correct buffer size.It is only necessary, if you need to call
EVP_EncodeUpdate
multiple times, because your data is exceedingly large or not available at once.