我怎么base64编码(解码)在C?

我有一个无符号的字符variables中的二进制数据。 我需要将它们转换成PEM base64在c。 我看着openssl库,但我找不到任何function。 有任何的身体有任何想法?

这是我正在使用的一个:

#include <stdint.h> #include <stdlib.h> static char encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; static char *decoding_table = NULL; static int mod_table[] = {0, 2, 1}; char *base64_encode(const unsigned char *data, size_t input_length, size_t *output_length) { *output_length = 4 * ((input_length + 2) / 3); char *encoded_data = malloc(*output_length); if (encoded_data == NULL) return NULL; for (int i = 0, j = 0; i < input_length;) { uint32_t octet_a = i < input_length ? (unsigned char)data[i++] : 0; uint32_t octet_b = i < input_length ? (unsigned char)data[i++] : 0; uint32_t octet_c = i < input_length ? (unsigned char)data[i++] : 0; uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F]; encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F]; encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F]; encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F]; } for (int i = 0; i < mod_table[input_length % 3]; i++) encoded_data[*output_length - 1 - i] = '='; return encoded_data; } unsigned char *base64_decode(const char *data, size_t input_length, size_t *output_length) { if (decoding_table == NULL) build_decoding_table(); if (input_length % 4 != 0) return NULL; *output_length = input_length / 4 * 3; if (data[input_length - 1] == '=') (*output_length)--; if (data[input_length - 2] == '=') (*output_length)--; unsigned char *decoded_data = malloc(*output_length); if (decoded_data == NULL) return NULL; for (int i = 0, j = 0; i < input_length;) { uint32_t sextet_a = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; uint32_t sextet_b = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; uint32_t sextet_c = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; uint32_t sextet_d = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]]; uint32_t triple = (sextet_a << 3 * 6) + (sextet_b << 2 * 6) + (sextet_c << 1 * 6) + (sextet_d << 0 * 6); if (j < *output_length) decoded_data[j++] = (triple >> 2 * 8) & 0xFF; if (j < *output_length) decoded_data[j++] = (triple >> 1 * 8) & 0xFF; if (j < *output_length) decoded_data[j++] = (triple >> 0 * 8) & 0xFF; } return decoded_data; } void build_decoding_table() { decoding_table = malloc(256); for (int i = 0; i < 64; i++) decoding_table[(unsigned char) encoding_table[i]] = i; } void base64_cleanup() { free(decoding_table); } 

请记住,这不会做解码时的任何错误检查 – 非基地64编码的数据将得到处理。

但是你也可以在openssl( openssl enc命令做到这一点….),看看BIO_f_base64()函数

glib具有base64编码的function: https : //developer.gnome.org/glib/stable/glib-Base64-Encoding.html

我知道这个问题是相当古老的,但是我提供的解决scheme数量让我感到困惑 – 他们中的每一个都声称速度更快,更好。 我把一个项目放在github上来比较base64编码器和解码器: https : //github.com/gaspardpetit/base64/

在这一点上,我并没有将自己局限于Calgorithm – 如果一个实现在C ++中performance良好,可以很容易地将其返回到C.还使用Visual Studio 2015进行了testing。如果有人想要用clang /海湾合作委员会,做我的客人。

最快的编码器我发现的两个最快的编码器实现是Jouni Malinen的http://web.mit.edu/freebsd/head/contrib/wpa/src/utils/base64.c和Apache在https://opensource.apple .com / source / QuickTimeStreamingServer / QuickTimeStreamingServer-452 / CommonUtilitiesLib / base64.c 。

下面是使用到目前为止我testing过的不同algorithm编码32K数据的时间(微秒)

 jounimalinen 25.1544 apache 25.5309 NibbleAndAHalf 38.4165 internetsoftwareconsortium 48.2879 polfosol 48.7955 wikibooks_org_c 51.9659 gnome 74.8188 elegantdice 118.899 libb64 120.601 manuelmartinez 120.801 arduino 126.262 daedalusalpha 126.473 CppCodec 151.866 wikibooks_org_cpp 343.2 adp_gmbh 381.523 LihO 406.693 libcurl 3246.39 user152949 4828.21 

(RenéNyffenegger的解决scheme,在这个问题的另一个答案相信,在这里列为adp_gmbh)。

这是来自Jouni Malinen的,我稍微修改了一个返回一个std :: string:

 /* * Base64 encoding/decoding (RFC1341) * Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. */ // 2016-12-12 - Gaspard Petit : Slightly modified to return a std::string // instead of a buffer allocated with malloc. #include <string> static const unsigned char base64_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /** * base64_encode - Base64 encode * @src: Data to be encoded * @len: Length of the data to be encoded * @out_len: Pointer to output length variable, or %NULL if not used * Returns: Allocated buffer of out_len bytes of encoded data, * or empty string on failure */ std::string base64_encode(const unsigned char *src, size_t len) { unsigned char *out, *pos; const unsigned char *end, *in; size_t olen; olen = 4*((len + 2) / 3); /* 3-byte blocks to 4-byte */ if (olen < len) return std::string(); /* integer overflow */ std::string outStr; outStr.resize(olen); out = (unsigned char*)&outStr[0]; end = src + len; in = src; pos = out; while (end - in >= 3) { *pos++ = base64_table[in[0] >> 2]; *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; *pos++ = base64_table[in[2] & 0x3f]; in += 3; } if (end - in) { *pos++ = base64_table[in[0] >> 2]; if (end - in == 1) { *pos++ = base64_table[(in[0] & 0x03) << 4]; *pos++ = '='; } else { *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; *pos++ = base64_table[(in[1] & 0x0f) << 2]; } *pos++ = '='; } return outStr; } 

最快的解码器:这里是解码结果,我必须承认我有点惊讶:

 polfosol 45.2335 wikibooks_org_c 74.7347 apache 77.1438 libb64 100.332 gnome 114.511 manuelmartinez 126.579 elegantdice 138.514 daedalusalpha 151.561 jounimalinen 206.163 arduino 335.95 wikibooks_org_cpp 350.437 CppCodec 526.187 internetsoftwareconsortium 862.833 libcurl 1280.27 LihO 1852.4 adp_gmbh 1934.43 user152949 5332.87 

Polfosol 在c ++中的base64解码片段的片段速度是最快的两倍。

这是为了完整起见的代码:

 static const int B64index[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 63, 62, 62, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 63, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 }; std::string b64decode(const void* data, const size_t len) { unsigned char* p = (unsigned char*)data; int pad = len > 0 && (len % 4 || p[len - 1] == '='); const size_t L = ((len + 3) / 4 - pad) * 4; std::string str(L / 4 * 3 + pad, '\0'); for (size_t i = 0, j = 0; i < L; i += 4) { int n = B64index[p[i]] << 18 | B64index[p[i + 1]] << 12 | B64index[p[i + 2]] << 6 | B64index[p[i + 3]]; str[j++] = n >> 16; str[j++] = n >> 8 & 0xFF; str[j++] = n & 0xFF; } if (pad) { int n = B64index[p[L]] << 18 | B64index[p[L + 1]] << 12; str[str.size() - 1] = n >> 16; if (len > L + 2 && p[L + 2] != '=') { n |= B64index[p[L + 2]] << 6; str.push_back(n >> 8 & 0xFF); } } return str; } 

libb64具有C和C ++ API。 这是轻量级的,也许是最快的公开可用的实现。 这也是一个专用的独立base64编码库,如果你不需要来自使用OpenSSL或glib等更大的库的所有其他东西,那么这个库就可以很好。

我需要在std :: string上工作的C ++实现。 没有一个答案满足我的需求,我需要简单的双重function的编码和解码解决scheme,但我懒得编写我自己的代码,所以我发现这个:

http://www.adp-gmbh.ch/cpp/common/base64.html

代码积分请去RenéNyffenegger。

把下面的代码,以防万一站点宕机:

base64.cpp

 /* base64.cpp and base64.h Copyright (C) 2004-2008 René Nyffenegger This source code is provided 'as-is', without any express or implied warranty. In no event will the author be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this source code must not be misrepresented; you must not claim that you wrote the original source code. If you use this source code in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original source code. 3. This notice may not be removed or altered from any source distribution. René Nyffenegger rene.nyffenegger@adp-gmbh.ch */ #include "base64.h" #include <iostream> static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/"; static inline bool is_base64(unsigned char c) { return (isalnum(c) || (c == '+') || (c == '/')); } std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) { std::string ret; int i = 0; int j = 0; unsigned char char_array_3[3]; unsigned char char_array_4[4]; while (in_len--) { char_array_3[i++] = *(bytes_to_encode++); if (i == 3) { char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[3] = char_array_3[2] & 0x3f; for(i = 0; (i <4) ; i++) ret += base64_chars[char_array_4[i]]; i = 0; } } if (i) { for(j = i; j < 3; j++) char_array_3[j] = '\0'; char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); char_array_4[3] = char_array_3[2] & 0x3f; for (j = 0; (j < i + 1); j++) ret += base64_chars[char_array_4[j]]; while((i++ < 3)) ret += '='; } return ret; } std::string base64_decode(std::string const& encoded_string) { int in_len = encoded_string.size(); int i = 0; int j = 0; int in_ = 0; unsigned char char_array_4[4], char_array_3[3]; std::string ret; while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { char_array_4[i++] = encoded_string[in_]; in_++; if (i ==4) { for (i = 0; i <4; i++) char_array_4[i] = base64_chars.find(char_array_4[i]); char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; for (i = 0; (i < 3); i++) ret += char_array_3[i]; i = 0; } } if (i) { for (j = i; j <4; j++) char_array_4[j] = 0; for (j = 0; j <4; j++) char_array_4[j] = base64_chars.find(char_array_4[j]); char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; } return ret; } 

base64.h

 #include <string> std::string base64_encode(unsigned char const* , unsigned int len); std::string base64_decode(std::string const& s); 

用法

 const std::string s = "test"; std::string encoded = base64_encode(reinterpret_cast<const unsigned char*>(s.c_str()), s.length()); std::string decoded = base64_decode(encoded); 

GNU coreutils在lib / base64中有。 这是一个有点臃肿,但处理像EBCDIC的东西。 你也可以自己玩,例如,

 char base64_digit (n) unsigned n; { if (n < 10) return n - '0'; else if (n < 10 + 26) return n - 'a'; else if (n < 10 + 26 + 26) return n - 'A'; else assert(0); return 0; } unsigned char base64_decode_digit(char c) { switch (c) { case '=' : return 62; case '.' : return 63; default : if (isdigit(c)) return c - '0'; else if (islower(c)) return c - 'a' + 10; else if (isupper(c)) return c - 'A' + 10 + 26; else assert(0); } return 0xff; } unsigned base64_decode(char *s) { char *p; unsigned n = 0; for (p = s; *p; p++) n = 64 * n + base64_decode_digit(*p); return n; } 

通过这些礼物让所有的人都知道,你不应该混淆“自己玩耍”和“执行标准”。 Yeesh。

这是我使用OpenSSL的解决scheme。

 /* A BASE-64 ENCODER AND DECODER USING OPENSSL */ #include <openssl/pem.h> #include <string.h> //Only needed for strlen(). char *base64encode (const void *b64_encode_this, int encode_this_many_bytes){ BIO *b64_bio, *mem_bio; //Declares two OpenSSL BIOs: a base64 filter and a memory BIO. BUF_MEM *mem_bio_mem_ptr; //Pointer to a "memory BIO" structure holding our base64 data. b64_bio = BIO_new(BIO_f_base64()); //Initialize our base64 filter BIO. mem_bio = BIO_new(BIO_s_mem()); //Initialize our memory sink BIO. BIO_push(b64_bio, mem_bio); //Link the BIOs by creating a filter-sink BIO chain. BIO_set_flags(b64_bio, BIO_FLAGS_BASE64_NO_NL); //No newlines every 64 characters or less. BIO_write(b64_bio, b64_encode_this, encode_this_many_bytes); //Records base64 encoded data. BIO_flush(b64_bio); //Flush data. Necessary for b64 encoding, because of pad characters. BIO_get_mem_ptr(mem_bio, &mem_bio_mem_ptr); //Store address of mem_bio's memory structure. BIO_set_close(mem_bio, BIO_NOCLOSE); //Permit access to mem_ptr after BIOs are destroyed. BIO_free_all(b64_bio); //Destroys all BIOs in chain, starting with b64 (ie the 1st one). BUF_MEM_grow(mem_bio_mem_ptr, (*mem_bio_mem_ptr).length + 1); //Makes space for end null. (*mem_bio_mem_ptr).data[(*mem_bio_mem_ptr).length] = '\0'; //Adds null-terminator to tail. return (*mem_bio_mem_ptr).data; //Returns base-64 encoded data. (See: "buf_mem_st" struct). } char *base64decode (const void *b64_decode_this, int decode_this_many_bytes){ BIO *b64_bio, *mem_bio; //Declares two OpenSSL BIOs: a base64 filter and a memory BIO. char *base64_decoded = calloc( (decode_this_many_bytes*3)/4+1, sizeof(char) ); //+1 = null. b64_bio = BIO_new(BIO_f_base64()); //Initialize our base64 filter BIO. mem_bio = BIO_new(BIO_s_mem()); //Initialize our memory source BIO. BIO_write(mem_bio, b64_decode_this, decode_this_many_bytes); //Base64 data saved in source. BIO_push(b64_bio, mem_bio); //Link the BIOs by creating a filter-source BIO chain. BIO_set_flags(b64_bio, BIO_FLAGS_BASE64_NO_NL); //Don't require trailing newlines. int decoded_byte_index = 0; //Index where the next base64_decoded byte should be written. while ( 0 < BIO_read(b64_bio, base64_decoded+decoded_byte_index, 1) ){ //Read byte-by-byte. decoded_byte_index++; //Increment the index until read of BIO decoded data is complete. } //Once we're done reading decoded data, BIO_read returns -1 even though there's no error. BIO_free_all(b64_bio); //Destroys all BIOs in chain, starting with b64 (ie the 1st one). return base64_decoded; //Returns base-64 decoded data with trailing null terminator. } /*Here's one way to base64 encode/decode using the base64encode() and base64decode functions.*/ int main(void){ char data_to_encode[] = "Base64 encode this string!"; //The string we will base-64 encode. int bytes_to_encode = strlen(data_to_encode); //Number of bytes in string to base64 encode. char *base64_encoded = base64encode(data_to_encode, bytes_to_encode); //Base-64 encoding. int bytes_to_decode = strlen(base64_encoded); //Number of bytes in string to base64 decode. char *base64_decoded = base64decode(base64_encoded, bytes_to_decode); //Base-64 decoding. printf("Original character string is: %s\n", data_to_encode); //Prints our initial string. printf("Base-64 encoded string is: %s\n", base64_encoded); //Prints base64 encoded string. printf("Base-64 decoded string is: %s\n", base64_decoded); //Prints base64 decoded string. free(base64_encoded); //Frees up the memory holding our base64 encoded data. free(base64_decoded); //Frees up the memory holding our base64 decoded data. } 

这是我一直使用多年的解码器…

  static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const int BASE64_INPUT_SIZE = 57; BOOL isbase64(char c) { return c && strchr(table, c) != NULL; } inline char value(char c) { const char *p = strchr(table, c); if(p) { return p-table; } else { return 0; } } int UnBase64(unsigned char *dest, const unsigned char *src, int srclen) { *dest = 0; if(*src == 0) { return 0; } unsigned char *p = dest; do { char a = value(src[0]); char b = value(src[1]); char c = value(src[2]); char d = value(src[3]); *p++ = (a << 2) | (b >> 4); *p++ = (b << 4) | (c >> 2); *p++ = (c << 6) | d; if(!isbase64(src[1])) { p -= 2; break; } else if(!isbase64(src[2])) { p -= 2; break; } else if(!isbase64(src[3])) { p--; break; } src += 4; while(*src && (*src == 13 || *src == 10)) src++; } while(srclen-= 4); *p = 0; return p-dest; } 

我写了一个和C ++一起使用的,它非常快速,适用于stream,免费和开源:

https://tmplusplus.svn.sourceforge.net/svnroot/tmplusplus/trunk/src/

随意使用它,如果它适合你的目的。

编辑:通过请求内联添加代码。

性能提升通过使用查找表进行编码和解码。 _UINT8是大多数操作系统上的unsigned char

 /** Static Base64 character encoding lookup table */ const char CBase64::encodeCharacterTable[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /** Static Base64 character decoding lookup table */ const char CBase64::decodeCharacterTable[256] = { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 ,-1,62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21 ,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1}; /*! \brief Encodes binary data to base 64 character data \param in The data to encode \param out The encoded data as characters */ void CBase64::Encode(std::istream &in, std::ostringstream &out) { char buff1[3]; char buff2[4]; _UINT8 i=0, j; while(in.readsome(&buff1[i++], 1)) if (i==3) { out << encodeCharacterTable[(buff1[0] & 0xfc) >> 2]; out << encodeCharacterTable[((buff1[0] & 0x03) << 4) + ((buff1[1] & 0xf0) >> 4)]; out << encodeCharacterTable[((buff1[1] & 0x0f) << 2) + ((buff1[2] & 0xc0) >> 6)]; out << encodeCharacterTable[buff1[2] & 0x3f]; i=0; } if (--i) { for(j=i;j<3;j++) buff1[j] = '\0'; buff2[0] = (buff1[0] & 0xfc) >> 2; buff2[1] = ((buff1[0] & 0x03) << 4) + ((buff1[1] & 0xf0) >> 4); buff2[2] = ((buff1[1] & 0x0f) << 2) + ((buff1[2] & 0xc0) >> 6); buff2[3] = buff1[2] & 0x3f; for (j=0;j<(i+1);j++) out << encodeCharacterTable[buff2[j]]; while(i++<3) out << '='; } } /*! \brief Decodes base 64 character data to binary data \param in The character data to decode \param out The decoded data */ void CBase64::Decode(std::istringstream &in, std::ostream &out) { char buff1[4]; char buff2[4]; _UINT8 i=0, j; while(in.readsome(&buff2[i], 1) && buff2[i] != '=') { if (++i==4) { for (i=0;i!=4;i++) buff2[i] = decodeCharacterTable[buff2[i]]; out << (char)((buff2[0] << 2) + ((buff2[1] & 0x30) >> 4)); out << (char)(((buff2[1] & 0xf) << 4) + ((buff2[2] & 0x3c) >> 2)); out << (char)(((buff2[2] & 0x3) << 6) + buff2[3]); i=0; } } if (i) { for (j=i;j<4;j++) buff2[j] = '\0'; for (j=0;j<4;j++) buff2[j] = decodeCharacterTable[buff2[j]]; buff1[0] = (buff2[0] << 2) + ((buff2[1] & 0x30) >> 4); buff1[1] = ((buff2[1] & 0xf) << 4) + ((buff2[2] & 0x3c) >> 2); buff1[2] = ((buff2[2] & 0x3) << 6) + buff2[3]; for (j=0;j<(i-1); j++) out << (char)buff1[j]; } } 

如果人们需要一个c ++解决scheme,我把这个OpenSSL解决scheme放在一起(编码和解码)。 你需要链接到“encryption”库(这是OpenSSL)。 这已经被valgrind检查过泄漏(虽然你可以添加一些额外的错误检查代码,使它好一点 – 我知道至less写函数应该检查返回值)。

 #include <openssl/bio.h> #include <openssl/evp.h> #include <stdlib.h> string base64_encode( const string &str ){ BIO *base64_filter = BIO_new( BIO_f_base64() ); BIO_set_flags( base64_filter, BIO_FLAGS_BASE64_NO_NL ); BIO *bio = BIO_new( BIO_s_mem() ); BIO_set_flags( bio, BIO_FLAGS_BASE64_NO_NL ); bio = BIO_push( base64_filter, bio ); BIO_write( bio, str.c_str(), str.length() ); BIO_flush( bio ); char *new_data; long bytes_written = BIO_get_mem_data( bio, &new_data ); string result( new_data, bytes_written ); BIO_free_all( bio ); return result; } string base64_decode( const string &str ){ BIO *bio, *base64_filter, *bio_out; char inbuf[512]; int inlen; base64_filter = BIO_new( BIO_f_base64() ); BIO_set_flags( base64_filter, BIO_FLAGS_BASE64_NO_NL ); bio = BIO_new_mem_buf( (void*)str.c_str(), str.length() ); bio = BIO_push( base64_filter, bio ); bio_out = BIO_new( BIO_s_mem() ); while( (inlen = BIO_read(bio, inbuf, 512)) > 0 ){ BIO_write( bio_out, inbuf, inlen ); } BIO_flush( bio_out ); char *new_data; long bytes_written = BIO_get_mem_data( bio_out, &new_data ); string result( new_data, bytes_written ); BIO_free_all( bio ); BIO_free_all( bio_out ); return result; } 

这个解决scheme基于schulwitz答案(编码/解码使用OpenSSL),但它是为C + +(原来的问题是关于C,但这里已经有另一个C ++的答案),它使用错误检查(所以这是更安全的使用) :

 #include <openssl/bio.h> std::string base64_encode(const std::string &input) { BIO *p_bio_b64 = nullptr; BIO *p_bio_mem = nullptr; try { // make chain: p_bio_b64 <--> p_bio_mem p_bio_b64 = BIO_new(BIO_f_base64()); if (!p_bio_b64) { throw std::runtime_error("BIO_new failed"); } BIO_set_flags(p_bio_b64, BIO_FLAGS_BASE64_NO_NL); //No newlines every 64 characters or less p_bio_mem = BIO_new(BIO_s_mem()); if (!p_bio_mem) { throw std::runtime_error("BIO_new failed"); } BIO_push(p_bio_b64, p_bio_mem); // write input to chain // write sequence: input -->> p_bio_b64 -->> p_bio_mem if (BIO_write(p_bio_b64, input.c_str(), input.size()) <= 0) { throw std::runtime_error("BIO_write failed"); } if (BIO_flush(p_bio_b64) <= 0) { throw std::runtime_error("BIO_flush failed"); } // get result char *p_encoded_data = nullptr; auto encoded_len = BIO_get_mem_data(p_bio_mem, &p_encoded_data); if (!p_encoded_data) { throw std::runtime_error("BIO_get_mem_data failed"); } std::string result(p_encoded_data, encoded_len); // clean BIO_free_all(p_bio_b64); return result; } catch (...) { if (p_bio_b64) { BIO_free_all(p_bio_b64); } throw; } } std::string base64_decode(const std::string &input) { BIO *p_bio_mem = nullptr; BIO *p_bio_b64 = nullptr; try { // make chain: p_bio_b64 <--> p_bio_mem p_bio_b64 = BIO_new(BIO_f_base64()); if (!p_bio_b64) { throw std::runtime_error("BIO_new failed"); } BIO_set_flags(p_bio_b64, BIO_FLAGS_BASE64_NO_NL); //Don't require trailing newlines p_bio_mem = BIO_new_mem_buf((void*)input.c_str(), input.length()); if (!p_bio_mem) { throw std::runtime_error("BIO_new failed"); } BIO_push(p_bio_b64, p_bio_mem); // read result from chain // read sequence (reverse to write): buf <<-- p_bio_b64 <<-- p_bio_mem std::vector<char> buf((input.size()*3/4)+1); std::string result; for (;;) { auto nread = BIO_read(p_bio_b64, buf.data(), buf.size()); if (nread < 0) { throw std::runtime_error("BIO_read failed"); } if (nread == 0) { break; } // eof result.append(buf.data(), nread); } // clean BIO_free_all(p_bio_b64); return result; } catch (...) { if (p_bio_b64) { BIO_free_all(p_bio_b64); } throw; } } 

请注意,base64_decode返回空string,如果input不正确base64序列(openssl以这种方式工作)。

下面是接受答案的编码器的优化版本,也支持MIME和其他协议的断线(模拟优化可以应用于解码器):

  char *base64_encode(const unsigned char *data, size_t input_length, size_t *output_length, bool addLineBreaks) *output_length = 4 * ((input_length + 2) / 3); if (addLineBreaks) *output_length += *output_length / 38; // CRLF after each 76 chars char *encoded_data = malloc(*output_length); if (encoded_data == NULL) return NULL; UInt32 octet_a; UInt32 octet_b; UInt32 octet_c; UInt32 triple; int lineCount = 0; int sizeMod = size - (size % 3); // check if there is a partial triplet // adding all octet triplets, before partial last triplet for (; offset < sizeMod; ) { octet_a = data[offset++]; octet_b = data[offset++]; octet_c = data[offset++]; triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; encoded_data[mBufferPos++] = encoding_table[(triple >> 3 * 6) & 0x3F]; encoded_data[mBufferPos++] = encoding_table[(triple >> 2 * 6) & 0x3F]; encoded_data[mBufferPos++] = encoding_table[(triple >> 1 * 6) & 0x3F]; encoded_data[mBufferPos++] = encoding_table[(triple >> 0 * 6) & 0x3F]; if (addLineBreaks) { if (++lineCount == 19) { encoded_data[mBufferPos++] = 13; encoded_data[mBufferPos++] = 10; lineCount = 0; } } } // last bytes if (sizeMod < size) { octet_a = data[offset++]; // first octect always added octet_b = offset < size ? data[offset++] : (UInt32)0; // conditional 2nd octet octet_c = (UInt32)0; // last character is definitely padded triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; encoded_data[mBufferPos++] = encoding_table[(triple >> 3 * 6) & 0x3F]; encoded_data[mBufferPos++] = encoding_table[(triple >> 2 * 6) & 0x3F]; encoded_data[mBufferPos++] = encoding_table[(triple >> 1 * 6) & 0x3F]; encoded_data[mBufferPos++] = encoding_table[(triple >> 0 * 6) & 0x3F]; // add padding '=' sizeMod = size % 3; // last character is definitely padded encoded_data[mBufferPos - 1] = (byte)'='; if (sizeMod == 1) encoded_data[mBufferPos - 2] = (byte)'='; } }