Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

encrypting and serializing stl string and other containers

I have data in stl containers (vector). Each node in the vector is a structure which also contains stl strings.

struct record
{
string name;
string location;
int salary;
}

vector< record > employees;

I want to serialize employees but I also want to encrypt it before serializing.

my encryption function looks like this:

Encode(const char * inBfr, const int in_size, char ** outBfr, int& out_size )

By searching it looks like the stl standard doesn't require the memory of my structure to be contiguous so I can't just grab the memory of employees variable. Is there any other smart way that I can use this encoding function with my stl based structures/container? It is good for me that Encode function works in plain char * buffers so I know exactly what goes in and out but stl structures are not and I am tring to find a nice way so I can use stl with this function.

I am also opening to using any other stl containers if that helps.

like image 809
zar Avatar asked Dec 02 '22 21:12

zar


2 Answers

Although the element in the std::vector<T> are guaranteed to be laid out contiguously, this doesn't really help: the record you have may include padding and, more importantly, will store the std::string's content external to the std::string object (in case the small string optimization is used, the value may be embedded inside the std::string but it will also contain a couple of bytes which are not part of the std::strings value). Thus, you best option is to format your record and encrypt the formatted string.

The formatting is straight forward but personally I would encapsulate the encoding function into a simple std::streambuf so that the encryption can be done by a filtering stream buffer. Given the signature you gave, this could look something like this:

class encryptbuf
    : public std::streambuf {
    std::streambuf* d_sbuf;
    char            d_buffer[1024];
public:
    encryptbuf(std::streambuf* sbuf)
        : d_sbuf(sbuf) {
        this->setp(this->d_buffer, this->d_buffer + sizeof(this->d_buffer) - 1);
    }
    int overflow(int c) {
        if (c != std::char_traits<char>::eof()) {
            *this->pptr() = std::char_traits<char>::to_char_type(c);
            this->pbump(1);
        }
        return this->pubsync()? std::char_traits<char>::eof(): std::char_traits<char>::not_eof(c);
    }
    int sync() {
        char* out(0);
        int   size(0);
        Encode(this->pbase(), this->pptr() - this->pbase(), &out, size);
        this->d_sbuf->sputn(out, size);
        delete[] out; // dunno: it seems the output buffer is allocated but how?
        this->setp(this->pbase(), this->epptr());
        return this->d_sbuf->pubsync();
    }
};

int main() {
    encryptbuf    sbuf(std::cout.rdbuf());
    std::ostream eout(&sbuf);
    eout << "print something encoded to standard output\n" << std::flush;
}

Now, creating an output operator for your records just printing to an std::ostream can be used to create an encoded

like image 94
Dietmar Kühl Avatar answered Dec 18 '22 06:12

Dietmar Kühl


It's probably easiest to serialize your structure into a string, then encrypt the string. For example:

std::ostringstream buffer;

buffer << a_record.name << "\n" << a_record.location << "\n" << a_record.salary;

encode(buffer.str().c_str(), buffer.str().length(), /* ... */);

If it were me, I'd probably write encode (or at least a wrapper for it) to take input (and probably produce output) in a vector, string, or stream though.

If you want to get ambitious, there are other possibilities. First of all, @MooingDuck raises a good point that it's often worthwhile to overload operator<< for the class, instead of working with the individual items all the time. This will typically be a small function similar to what's above:

std::ostream &operator<<(std::ostream &os, record const &r) { 
    return os << r.name << "\n" << r.location << "\n" << r.salary;
}

Using this, you'd just have:

std::ostringstream os;
os << a_record;

encode(os.str().c_str(), os.str().length(), /* ... */);

Second, if you want to get really ambitious, you can put the encryption into (for one example) a codecvt facet, so you can automatically encrypt all the data as you write it to a stream, and decrypt it as you read it back in. Another possibility is to build the encryption into a filtering streambuf object instead. The codecvt facet is probably the method that should theoretically be preferred, but the streambuf is almost certainly easier to implement, with less unrelated "stuff" involved.

like image 24
Jerry Coffin Avatar answered Dec 18 '22 06:12

Jerry Coffin