用OpenSSL 做Base64 编解码(C++)

时间:2022-11-21 18:25:12

参考

1)http://www.ioncannon.net/programming/34/howto-base64-encode-with-cc-and-openssl/
2)http://www.ioncannon.net/programming/122/howto-base64-decode-with-cc-and-openssl/
3)http://*.com/questions/12109960/openssl-base64-decoding-bio-read-returns-0
4)http://*.com/questions/5288076/doing-base64-encoding-and-decoding-in-openssl-c


main.cpp

#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <string.h>
#include <string>
#include <iostream>
using namespace std;

char * Base64Encode(const char* input, int length, bool with_new_line);
char * Base64Decode(char* input, int length, bool with_new_line);

int main(int argc, char* argv[])
{
cout << "With new line? y/n ";
string option;
cin >> option;
bool with_new_line = ( ("y" == option || "Y" == option) ? true : false );

string enc_input = "Henry Alfred Kissinger is a German-born American writer, political scientist, diplomat, and businessman. A recipient of the Nobel Peace Prize, he served as National Security Advisor and later concurrently as Secretary of State in the administrations of Presidents Richard Nixon and Gerald Ford.";

cout << endl << "To be encoded:" << endl << "~" << enc_input << "~" << endl << endl;

char * enc_output = Base64Encode(enc_input.c_str(), enc_input.length(), with_new_line);
cout << "Base64 Encoded:" << endl << "~" << enc_output << "~" << endl << endl;

string dec_input = enc_output;
char * dec_output = Base64Decode((char *)dec_input.c_str(), dec_input.length(), with_new_line);
cout << "Base64 Decoded:" << endl << "~" << dec_output << "~" << endl << endl;

free(enc_output);
free(dec_output);
}

char * Base64Encode(const char * input, int length, bool with_new_line)
{
BIO * bmem = NULL;
BIO * b64 = NULL;
BUF_MEM * bptr = NULL;

b64 = BIO_new(BIO_f_base64());
if(!with_new_line) {
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
}
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 + 1);
memcpy(buff, bptr->data, bptr->length);
buff[bptr->length] = 0;

BIO_free_all(b64);

return buff;
}

char * Base64Decode(char * input, int length, bool with_new_line)
{
BIO * b64 = NULL;
BIO * bmem = NULL;
char * buffer = (char *)malloc(length);
memset(buffer, 0, length);

b64 = BIO_new(BIO_f_base64());
if(!with_new_line) {
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
}
bmem = BIO_new_mem_buf(input, length);
bmem = BIO_push(b64, bmem);
BIO_read(bmem, buffer, length);

BIO_free_all(bmem);

return buffer;
}

Makefile

INC_OPT = -I/usr/include/openssl
LNK_OPT = -g -L/usr/lib64/ -lssl

all:
g++ main.cpp -g -o test $(INC_OPT) $(LNK_OPT)

执行结果1(编码结果每64个字符换行一次)

[root@ampcommons02 base64-test]# ./test
With new line? y/n y

To be encoded:
~Henry Alfred Kissinger is a German-born American writer, political scientist, diplomat, and businessman. A recipient of the Nobel Peace Prize, he served as National Security Advisor and later concurrently as Secretary of State in the administrations of Presidents Richard Nixon and Gerald Ford.~

Base64 Encoded:
~SGVucnkgQWxmcmVkIEtpc3NpbmdlciBpcyBhIEdlcm1hbi1ib3JuIEFtZXJpY2Fu
IHdyaXRlciwgcG9saXRpY2FsIHNjaWVudGlzdCwgZGlwbG9tYXQsIGFuZCBidXNp
bmVzc21hbi4gQSByZWNpcGllbnQgb2YgdGhlIE5vYmVsIFBlYWNlIFByaXplLCBo
ZSBzZXJ2ZWQgYXMgTmF0aW9uYWwgU2VjdXJpdHkgQWR2aXNvciBhbmQgbGF0ZXIg
Y29uY3VycmVudGx5IGFzIFNlY3JldGFyeSBvZiBTdGF0ZSBpbiB0aGUgYWRtaW5p
c3RyYXRpb25zIG9mIFByZXNpZGVudHMgUmljaGFyZCBOaXhvbiBhbmQgR2VyYWxk
IEZvcmQu
~

Base64 Decoded:
~Henry Alfred Kissinger is a German-born American writer, political scientist, diplomat, and businessman. A recipient of the Nobel Peace Prize, he served as National Security Advisor and later concurrently as Secretary of State in the administrations of Presidents Richard Nixon and Gerald Ford.~
执行结果2(编码结果不换行)
[root@ampcommons02 base64-test]# ./test
With new line? y/n n

To be encoded:
~Henry Alfred Kissinger is a German-born American writer, political scientist, diplomat, and businessman. A recipient of the Nobel Peace Prize, he served as National Security Advisor and later concurrently as Secretary of State in the administrations of Presidents Richard Nixon and Gerald Ford.~

Base64 Encoded:
~SGVucnkgQWxmcmVkIEtpc3NpbmdlciBpcyBhIEdlcm1hbi1ib3JuIEFtZXJpY2FuIHdyaXRlciwgcG9saXRpY2FsIHNjaWVudGlzdCwgZGlwbG9tYXQsIGFuZCBidXNpbmVzc21hbi4gQSByZWNpcGllbnQgb2YgdGhlIE5vYmVsIFBlYWNlIFByaXplLCBoZSBzZXJ2ZWQgYXMgTmF0aW9uYWwgU2VjdXJpdHkgQWR2aXNvciBhbmQgbGF0ZXIgY29uY3VycmVudGx5IGFzIFNlY3JldGFyeSBvZiBTdGF0ZSBpbiB0aGUgYWRtaW5pc3RyYXRpb25zIG9mIFByZXNpZGVudHMgUmljaGFyZCBOaXhvbiBhbmQgR2VyYWxkIEZvcmQu~

Base64 Decoded:
~Henry Alfred Kissinger is a German-born American writer, political scientist, diplomat, and businessman. A recipient of the Nobel Peace Prize, he served as National Security Advisor and later concurrently as Secretary of State in the administrations of Presidents Richard Nixon and Gerald Ford.~
注意
1) 参考1的原文中,Encode示例代码中有一处错误:base64("YOYO!", sizeof("YOYO!")) 应该是 base64("YOYO!", strlen("YOYO!"))

2)参考1的原文中,编码结果中,每64个字符换行一次,整个编码后的字符串的末尾也有换行。这是因为没有做BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL) 操作

3)参考1的原文中,下面红色标记的地方的用法有误!事实上,都要加1否则,解码还原出来的字符串与编码前的原始字符串相比,丢失两个字符

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;
}

4)上面的实例代码中,Base64Encode() 函数和 Base64Decode() 函数的返回值的buffer 是在Base64Encode() 函数和 Base64Decode() 里面申请的,因此,调用者在使用完这些buffer以后,自己free这些buffer(30、31行)

5)上面的示例代码中,41-43行、67-69行对“编码结果是否有换行”做了区分。这样做是为了方便兼容不带换行的base64编码方式,比如Java的程序用不带换行的base64方式编码的结果,C++也要能解码;或者Java程序只对不带换行的字符串做解码,那么C++代码也要能用不带换行的方式做base64编码。(Java SDK的base64编解码默认是采取不带换行的方式,如果设置了“chunk”属性,可以支持带换行的方式)。注意,这里的换行指的是一个'\n'

6)用openssl 命令行做base64编解码是这样的:

[root@ampcommons02 base64-test]# echo -n "Henry Alfred Kissinger is a German-born American writer, political scientist, diplomat, and businessman." | openssl enc -base64
SGVucnkgQWxmcmVkIEtpc3NpbmdlciBpcyBhIEdlcm1hbi1ib3JuIEFtZXJpY2Fu
IHdyaXRlciwgcG9saXRpY2FsIHNjaWVudGlzdCwgZGlwbG9tYXQsIGFuZCBidXNp
bmVzc21hbi4=
[root@ampcommons02 base64-test]# echo "SGVucnkgQWxmcmVkIEtpc3NpbmdlciBpcyBhIEdlcm1hbi1ib3JuIEFtZXJpY2Fu
> IHdyaXRlciwgcG9saXRpY2FsIHNjaWVudGlzdCwgZGlwbG9tYXQsIGFuZCBidXNp
> bmVzc21hbi4=
> " | openssl enc -base64 -d
Henry Alfred Kissinger is a German-born American writer, political scientist, diplomat, and businessman.[root@ampcommons02 base64-test]#

由上可见,用openssl命令行做base64编码的结果是每64个字符换行一次,整个编码后的字符串的末尾也有换行;同样,用openssl命令做base64解码的时候,输入的带解码字符串也必须是“每64个字符换行一次,整个编码后的字符串的末尾也有换行”的