Program Listing for File base64.cpp
↰ Return to documentation for file (src/base64.cpp
)
// base64 encodig and decoding.
//
// Based on the implementations by
// Jouni Malinen <j@w1.fi> and contributors from wpa_supplicant and hostapd in
// http://web.mit.edu/freebsd/head/contrib/wpa/ and
// http://web.mit.edu/freebsd/head/contrib/wpa/src/utils/base64.c and
// http://web.mit.edu/freebsd/head/contrib/wpa/src/utils/base64.h
//
// Published under a 3-clause BSD license
//
#include <string>
#include <cstring>
#include <stdexcept>
#include "crpropa/base64.h"
namespace crpropa
{
//Alphabet used
static const unsigned char encode_alphabet[65] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static int decode_alphabet[256] = {-1};
std::string Base64::encode(const unsigned char *src, size_t len)
{
size_t olen = 4*((len + 2) / 3); /* 3-byte blocks to 4-byte */
if (olen < len)
throw std::runtime_error("Integer overflow in Base64::encoding, data to large!");
std::string outStr;
outStr.resize(olen);
unsigned char *out = (unsigned char*) outStr.c_str();
unsigned char *pos = out;
const unsigned char *end, *in;
end = src + len;
in = src;
while (end - in >= 3) {
*pos++ = encode_alphabet[in[0] >> 2];
*pos++ = encode_alphabet[((in[0] & 0x03) << 4) | (in[1] >> 4)];
*pos++ = encode_alphabet[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
*pos++ = encode_alphabet[in[2] & 0x3f];
in += 3;
}
if (end - in) {
*pos++ = encode_alphabet[in[0] >> 2];
if (end - in == 1) {
*pos++ = encode_alphabet[(in[0] & 0x03) << 4];
*pos++ = '=';
}
else {
*pos++ = encode_alphabet[((in[0] & 0x03) << 4) |
(in[1] >> 4)];
*pos++ = encode_alphabet[(in[1] & 0x0f) << 2];
}
*pos++ = '=';
}
return outStr;
}
std::string Base64::decode(const std::string &data)
{
const unsigned char *src = (unsigned char*) data.c_str();
size_t len = data.size();
if (decode_alphabet[0] == -1)
{ // build decode alphabet
std::memset(decode_alphabet, 0x80, 256);
for (size_t i = 0; i < sizeof(encode_alphabet) - 1; i++)
decode_alphabet[encode_alphabet[i]] = (unsigned char) i;
decode_alphabet['='] = 0;
}
size_t olen = 0;
for (size_t i = 0; i < len; i++) {
if (decode_alphabet[src[i]] != 0x80)
olen++;
}
if (olen == 0 || olen % 4)
throw std::runtime_error("Base64 decode, invalid input size");
olen = olen / 4 * 3;
std::string str;
str.resize(olen);
unsigned char *out = (unsigned char*) str.c_str();
unsigned char *pos = out;
size_t count = 0;
int pad = 0;
unsigned char block[4];
for (size_t i = 0; i < len; i++) {
unsigned char tmp = decode_alphabet[src[i]];
if (tmp == 0x80)
continue;
if (src[i] == '=')
pad++;
block[count] = tmp;
count++;
if (count == 4) {
*pos++ = (block[0] << 2) | (block[1] >> 4);
*pos++ = (block[1] << 4) | (block[2] >> 2);
*pos++ = (block[2] << 6) | block[3];
count = 0;
if (pad) {
if (pad == 1)
pos--;
else if (pad == 2)
pos -= 2;
else {
throw std::runtime_error("Base64 decode, invalid padding");
}
break;
}
}
}
return str;
}
};