12
votes

I trying to use boost base64 encoder, I found an example but I got and exception

typedef 
transform_width< binary_from_base64<std::string::const_iterator>, 8, 6 > it_binary_t

an I used

std::string b64E(it_binary_t(Encrip.begin()), it_binary_t(Encrip.end()));

I get it

Unhandled exception at 0x75b1b9bc in agentid_coder.exe: Microsoft C++ exception: boost::archive::iterators::dataflow_exception at memory location 0x0046ed94..

I found this workaround but I get the same result

 string dec( 
        it_binary_t(Encrip.begin()), 
        it_binary_t(Encrip.begin() + Encrip.length() - 1) 
        ); 

I am using MSVS2008 and boost 1.38

1
Base64 encoding functions using Boost C++ Library: stackoverflow.com/questions/34680998/…ap6491

1 Answers

37
votes

Unfortunately the combination of the two iterator_adaptors binary_from_base64 and transform_width is not a complete base64 encoder/decoder. Base64 represents groups of 24 bits (3 bytes) as 4 characters, each of which encodes 6 bits. If the input data is not an integer multiple of such 3 byte groups it has to be padded with one or two zero bytes. To indicate how many padding bytes were added, one or two = characters are appended to the encoded string.

transform_width, which is responsible for the 8bit binary to 6bit integer conversion does not apply this padding automatically, it has do be done by the user. A simple example:

#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 <iostream>
#include <string>

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

int main(int argc, char **argv) {
  typedef transform_width< binary_from_base64<remove_whitespace<string::const_iterator> >, 8, 6 > it_binary_t;
  typedef insert_linebreaks<base64_from_binary<transform_width<string::const_iterator,6,8> >, 72 > it_base64_t;
  string s;
  getline(cin, s, '\n');
  cout << "Your string is: '"<<s<<"'"<<endl;

  // Encode
  unsigned int writePaddChars = (3-s.length()%3)%3;
  string base64(it_base64_t(s.begin()),it_base64_t(s.end()));
  base64.append(writePaddChars,'=');

  cout << "Base64 representation: " << base64 << endl;

  // Decode
  unsigned int paddChars = count(base64.begin(), base64.end(), '=');
  std::replace(base64.begin(),base64.end(),'=','A'); // replace '=' by base64 encoding of '\0'
  string result(it_binary_t(base64.begin()), it_binary_t(base64.end())); // decode
  result.erase(result.end()-paddChars,result.end());  // erase padding '\0' characters
  cout << "Decoded: " << result << endl;
  return 0;
}

Note that I added the insert_linebreaks and remove_whitespace iterators, so that the base64 output is nicely formatted and base64 input with line breaks can be decoded. These are optional though.

Run with different input strings which require different padding:

$ ./base64example
Hello World!
Your string is: 'Hello World!'
Base64 representation: SGVsbG8gV29ybGQh
Decoded: Hello World!
$ ./base64example
Hello World!!
Your string is: 'Hello World!!'
Base64 representation: SGVsbG8gV29ybGQhIQ==
Decoded: Hello World!!
$ ./base64example
Hello World!!!
Your string is: 'Hello World!!!'
Base64 representation: SGVsbG8gV29ybGQhISE=
Decoded: Hello World!!!

You can check the base64 strings with this online-encoder/decoder.