Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Decode Base64 String Using Boost

Tags:

c++

base64

boost

I've been able to encode a std::vector<char> to Base64 using boost and the following code:

using namespace boost::archive::iterators;

std::string message(binary.begin(), binary.end());
std::stringstream os;
using base64_text = insert_linebreaks<base64_from_binary<transform_width<const char *, 6, 8>>, 72>;

std::copy(
    base64_text(message.c_str()),
    base64_text(message.c_str() + message.size()),
    ostream_iterator<char>(os)
);

return os.str();

I found this on Stackoverflow. Well, now I want to to the same thing backwards, putting in a Base64 formatted std::string and end up with a std::vector<char>. But I can't adapt my example to do the thing in reverse. I found some other code online, which works nice with a Hello World example, but when there's an actual bigger Base64 which also contains some critical characters like backslashes, the whole thing crashes.

This is what I'm doing now to decode:

using namespace std;
using namespace boost::archive::iterators;

typedef
    transform_width<
        binary_from_base64<string::const_iterator>, 8, 6
        > binary_t;
string dec(binary_t(str.begin()), binary_t(str.end()));
return dec;

It crashes in the last line before the return, when I'm about to create the string. Do you see what's wrong with it?

like image 253
DenverCoder21 Avatar asked Oct 15 '25 14:10

DenverCoder21


2 Answers

base64 requires both input and output to be padded into multiples of 3 and 4 respectively.

Here's a function for decoding base64 using boost:

#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/archive/iterators/insert_linebreaks.hpp>
#include <boost/archive/iterators/remove_whitespace.hpp>
#include <algorithm>    

std::string decode(std::string input)
{
  using namespace boost::archive::iterators;
  typedef transform_width<binary_from_base64<remove_whitespace
      <std::string::const_iterator> >, 8, 6> ItBinaryT;

  try
  {
    // If the input isn't a multiple of 4, pad with =
    size_t num_pad_chars((4 - input.size() % 4) % 4);
    input.append(num_pad_chars, '=');

    size_t pad_chars(std::count(input.begin(), input.end(), '='));
    std::replace(input.begin(), input.end(), '=', 'A');
    std::string output(ItBinaryT(input.begin()), ItBinaryT(input.end()));
    output.erase(output.end() - pad_chars, output.end());
    return output;
  }
  catch (std::exception const&)
  {
    return std::string("");
  }
}

It was taken from here, where an encoding function with padding using boost can also be found.

like image 148
kenba Avatar answered Oct 18 '25 06:10

kenba


I tried kenba's accepted solution and ran into a few problems I've fixed below. First, trailing whitespace will cause any remove_whitespace iterator to skip past end(), causing a memory fault. Second, because you are calculating padding on the unfiltered string, any base64 encoded string which has whitespace in it will yield the incorrect number of pad_chars. The solution is to pre-filter whitespace before doing anything else with the string.

#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/archive/iterators/insert_linebreaks.hpp>
#include <boost/archive/iterators/remove_whitespace.hpp>
#include <algorithm> 

inline void decode_base64( std::string input, std::vector<char>& output )
{
    using namespace boost::archive::iterators;
    typedef remove_whitespace<std::string::const_iterator> StripIt;
    typedef transform_width<binary_from_base64<std::string::const_iterator>, 8, 6> ItBinaryT;
    try
    {
        /// Trailing whitespace makes remove_whitespace barf because the iterator never == end().
        while (!input.empty() && std::isspace( input.back() )) { input.pop_back(); }
        input.swap( std::string( StripIt( input.begin() ), StripIt( input.end() ) ) );
        /// If the input isn't a multiple of 4, pad with =
        input.append( (4 - input.size() % 4) % 4, '=' );
        size_t pad_chars( std::count( input.end() - 4, input.end(), '=' ) );
        std::replace( input.end() - 4, input.end(), '=', 'A' );
        output.clear();
        output.reserve( input.size() * 1.3334 );
        output.assign( ItBinaryT( input.begin() ), ItBinaryT( input.end() ) );
        output.erase( output.end() - (pad_chars < 2 ? pad_chars : 2), output.end() );
    }
    catch (std::exception const&)
    {
        output.clear();
    }
}
like image 28
cowtung Avatar answered Oct 18 '25 07:10

cowtung



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!