gav gav - 11 months ago 49
C++ Question

Encryption of Objects stored to disk using C++ (for a Java Developer)

This is two questions in one but hopefully trivial to a C++ developer.

  1. How can I seralize an object so that I can write it to disk and retrieve it later in C++ or if this is the wrong keyword how can I write an object as a binary stream and recreate it later? Can I use inheritance to make a hierarchy of classes serializable?

  2. what's the simplest way to encrypt / decrypt a stream of binary data given that I have an encryption key;

    const vector &encryption_key

This is a proof of concept so the strength or infallibility of the encryption is less important than the code being simple and easy to explain.

I can expand on either part of the question as required, as you've probably guessed I need to persist some data to the hard disk in files and retrieve it later in another run of the application, the files are large and this is my way of caching data retrieved over the network.



Answer Source

Boost.Serialization is probably the best option for doing this in C++. If you want to save binary data you need to create a boost::archive::binary_oarchive and associate it to your file:

std::ofstream ofs("my_file.dat");
boost::archive::binary_oarchive oarch(ofs);

Any class you want to serialize must have a member function serialize with a special signature that the library can understand. For example:

class Foo
   int i;
   Baz baz;

   template<class Archive>
   void serialize(Archive &ar, unsigned int version) {
       ar & i;
       ar & baz; // Baz must be serializable

Note that there's built-in support for versioning but that's a more advanced topic.

Saving objects of your class to the binary archive is then very easy:

Foo foo;
oarch << foo;  // Serializes "foo"

The cool thing about Boost.Serialization is that same member function is used to deserialize the object. The only difference is that now you use an input archive:

std::ifstream ifs("my_file.dat");
boost::archive::binary_iarchive iarch(ofs);
Foo foo;  
iarch >> foo; // Deserializes "foo"

As for the encryption part, the Botan library seems to be pretty mature an its C++ unlike OpenSSL that it's C and so a bit painful to use. This is how I think you can do serialization + encryption under the same workflow (deserialization would be analogous):

  1. You associate your archive to an in-memory string instead of to a file:

    std::ostringstream oss;
    boost::archive::binary_oarchive oarch(oss);

    Everything you write to the archive will be stored in the string.

  2. You serialize your objects like you did before:

    Foo foo;
    oarch << foo;  // Serializes "foo" (data goes to the string)
  3. You use the Botan library to encrypt your string. Don't take this too literally but it should be something like:

    a) create a Botan memory data source associated to your string (the oss object).

    b) create a Botan data sink associated to the file where you want to write ("myfile.dat").

    c) create an encoder that suits your needs

    d) call the encode function as in encode(source, sink);

EDIT: Changed crypto recommendantion from OpenSSL to Botan.