Reputation: 835
I am using the following code snippet to base64 encode and decode a string using Boost C++ library.
//Base64 Encode Implementation using Boost C++ library
const std::string base64_padding[] = {"", "=", "=="};
std::string X_Privet_Token_Generator::base64_encode(const std::string & s)
{
namespace bai = boost::archive::iterators;
std::stringstream os;
// convert binary values to base64 characters
typedef bai::base64_from_binary
// retrieve 6 bit integers from a sequence of 8 bit bytes
<bai::transform_width<const char *, 6, 8> > base64_enc; // compose all the above operations in to a new iterator
std::copy(base64_enc(s.c_str()), base64_enc(s.c_str() + s.size()), std::ostream_iterator<char>(os));
os << base64_padding[s.size() % 3];
return os.str();
}
std::string X_Privet_Token_Generator::base64_decode(std::string & s)
{
namespace bai = boost::archive::iterators;
std::stringstream os;
// convert binary values to base64 characters
typedef bai::binary_from_base64
<bai::transform_width<const char *, 8, 6> > base64_dec;
unsigned int size = s.size();
// Remove the padding characters, cf.
if (size && s[size - 1] == '=')
{
--size;
if (size && s[size - 1] == '=')
--size;
}
if (size == 0)
return std::string();
LOGINFO("Hash decoded token : %s", s.c_str());
std::copy(base64_dec(s.data()), base64_dec(s.data() + size), std::ostream_iterator<char>(os));
std::cout<< os.str();
return os.str();
}
Encoding works well, however, while decoding I get the following error:
terminate called after throwing an instance of
boost::archive::iterators::dataflow_exception
what()
: attempt to decode a value not in base64 char set
Is it one of the padded characters that is causing this issue? Am I missing something here?
Upvotes: 1
Views: 5730
Reputation: 835
A more efficient solution for base64 encoding and decoding is as follows:
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/insert_linebreaks.hpp>
#include <boost/archive/iterators/remove_whitespace.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/archive/iterators/ostream_iterator.hpp>
#include <boost/algorithm/string.hpp>
#include <bits/stl_algo.h>
std::string X_Privet_Token_Generator::base64_encode(std::string s)
{
namespace bai = boost::archive::iterators;
std::stringstream os;
// convert binary values to base64 characters
typedef bai::base64_from_binary
// retrieve 6 bit integers from a sequence of 8 bit bytes
<bai::transform_width<char *, 6, 8> > base64_enc; // compose all the above operations in to a new iterator
std::copy(base64_enc(s.c_str()), base64_enc(s.c_str() + s.size()), std::ostream_iterator<char>(os));
os << base64_padding[s.size() % 3];
return os.str();
}
std::string X_Privet_Token_Generator::base64_decode(std::string s)
{
namespace bai = boost::archive::iterators;
std::stringstream os;
typedef bai::transform_width<bai::binary_from_base64<char * >, 8, 6>
base64_dec;
unsigned int size = s.size();
// Remove the padding characters.
if(size && s[size - 1] == '=') {
--size;
if(size && s[size - 1] == '=')
--size;
}
if(size == 0) return std::string();
unsigned int paddChars = count(s.begin(), s.end(), '=');
std::replace(s.begin(),s.end(), '=', 'A');
std::string decoded_token(base64_dec(s.c_str()), base64_dec(s.c_str() + size));
decoded_token.erase(decoded_token.end()-paddChars,decoded_token.end());
return decoded_token;
}
Upvotes: 0
Reputation: 835
Changing the
std::copy(base64_dec(s.data()), base64_dec(s.data() + size), std::ostream_iterator<char>(os))
to
return std::string( base64_dec(s.c_str()), base64_dec(s.c_str() + size))
resolved the issue.
Upvotes: 0
Reputation: 41
The padding characters '=' are part of the b64 encoded data and should not be removed before decoding. b64 is encoded in blocks of 4 character, I suspect that while decoding it reads a '\0' instead of an expected '=' at the end of the string.
Upvotes: 4