tags:

views:

62

answers:

3

I'd like to provide an std::ostream that may or may not, from the user's point of view, encrypt its contents.

Imagine some random function that uses an std::ostream&:

void write_stuff( std::ostream& stream ) {
    os << "stuff";
}

Whether stuff is output in cleartext or is encrypted is dependent on how the stream argument was initialized.

I'm thinking about inheriting from std::basic_streambuf, but I'm not sure it's the best way to go. I think the ideal scenario is some sort of filter object which is run before the contents are actually output. That way it'd be easy to chain operations, e.g. encrypting and then hex-encoding, which is a benefit that making my own basic_streambuf does not seem to give (not easily at least).

Any advices?

Thanks.

UPDATE: I followed the strategy laid out by the accepted answer. I found this article on writing a custom streambuf which performs XOR obfuscation to be extremely helpful as a starting point.

A: 

I'm not sure that what I'm about to suggest is exactly what you need (and its too complicated to be a comment), but have you ever heard of the stream manipulators ?

#include <iostream>
#include <iomanip>

int main(int, char**)
{
  int a = 10;
  std::cout << "a: " << a << std::endl; //outputs: "a: 10"
  std::cout << "a: " << std::hex << a << std::endl; //outputs: "a: a"
  std::cout << "a: " << std::dec << a << std::endl; //outputs: "a: 10"

  return EXIT_SUCCESS;
}

You may indeed use a similar pattern (this matches what you actually call a "filter" object) to somehow change the state of your custom stream object.

ereOn
+2  A: 

A streambuf can be implemented in terms of another arbitrary streambuf that's either passed in as an argument to the constructor or set with a special member function. And that allows you to stack streambuf implementations like you were thinking of.

You could even make a manipulator that uses the ostream's rdbuf function to get the current streambuf, call a function on your streambuf that sets the 'stacked' streambuf, and then calls rdbuf again to replace the ostream's streambuf with your own.

aes_ctr_streambuf encrypter(key);
zlib_streambuf compressor;
::std::cout << stack_streambuf(encrypter) << stack_streambuf(compressor);
Omnifarious
This is what I ended up doing. I wish there were an easier way of writing iostreams filters, though. Thanks.
Pedro d'Aquino
@Pedro - You're welcome. :-)
Omnifarious
+2  A: 

It is hard to describe in short what you have to do in order to create an I/O stream for the new source or sink. Luckily, Jonathan Turkanis and CodeRage, LLC have created very nice building blocks with exceptional documentation that can help you save hundreds of hours of research and development of new streams. The library is called Boost.Iostreams.

The second example in documentation exactly shows how to solve your problem.

Also, note that they already have an output stream with zip compression. So maybe you don't even need to write a single line of code.

Good luck!

Vlad Lazarenko
Yeah, Boost.Iostreams did come to mind. I'm trying to do this for a logging module, so I'd rather keep external dependencies to a minimum as to make it easier to add logs to an existing project (it is currently a single header file). If writing my own `streambuf` turns out to be too much of a hassle though, I'll surely look into Boost.Iostreams. Thanks.
Pedro d'Aquino
@Pedro d'Aquino: Just in case, you might want to look at `bcp` utility. It extracts parts of the Boost so you can use them in your project and not worry about depending on the whole Boost project. See http://www.boost.org/doc/libs/1_41_0/tools/bcp/bcp.html
Vlad Lazarenko