Boost logo

Boost Users :

Subject: [Boost-users] Iostreams with two filters throws exception
From: NuSkooler (nuskooler_at_[hidden])
Date: 2013-08-08 01:37:45


I've been attempting to use Boost.Iostreams with two filters to compress +
encrypt ("out") and decrypt + uncompress ("in"). This works for some files,
while others throw an exception during the "in" phase. If I remove either
of the filters for out/in (e.g. remove the compress or the encrypt)
everything works fine -- the issue only occurs with two filters chained.

>From what I understand in the documentation, this should be supported, but
I must be missing something. Below is the relevant portions of my code:

Input & output cipher filters (note: I'm using Boost.Crypto, and
boost::crypto::rc4_cipher specifically)

template <typename StreamCipherT>
class StreamCipherFilterBase
{
public:
typedef char char_type;

StreamCipherFilterBase(const std::string& key)
{
m_cipher.set_key(key.data(), static_cast<unsigned int>(key.length()));
}
protected:
    char m_buffer[1024 * 2]; // 2k internal buffer size
    StreamCipherT m_cipher;
};

template <typename StreamCipherT>
class StreamCipherEncryptFilter
: public StreamCipherFilterBase<StreamCipherT>
{
public:
typedef boost::iostreams::multichar_output_filter_tag category;

StreamCipherEncryptFilter(const std::string& key)
: StreamCipherFilterBase<StreamCipherT>(key)
{
}

template<typename Sink>
std::streamsize write(Sink& snk, const char* s, std::streamsize n)
{
std::streamsize written = 0;
std::streamsize remain = n;
std::streamsize eat;
while(remain) {
eat = remain < sizeof(StreamCipherFilterBase<StreamCipherT>::m_buffer) ?
                remain :
sizeof(StreamCipherFilterBase<StreamCipherT>::m_buffer);
StreamCipherFilterBase<StreamCipherT>::m_cipher.encrypt(
s,
StreamCipherFilterBase<StreamCipherT>::m_buffer,
eat);
written += boost::iostreams::write(snk,
StreamCipherFilterBase<StreamCipherT>::m_buffer, eat);
remain -= eat;
s += eat;
}
return written;
}
};

template <typename StreamCipherT>
class StreamCipherDecryptFilter
: public StreamCipherFilterBase<StreamCipherT>
{
public:
typedef boost::iostreams::multichar_input_filter_tag category;

StreamCipherDecryptFilter(const std::string& key)
: StreamCipherFilterBase<StreamCipherT>(key)
{
}

template<typename Source>
std::streamsize read(Source& src, char* s, std::streamsize n)
{
const std::streamsize read = boost::iostreams::read(src, s, n);
        if(EOF == read) {
            return EOF;
        }
StreamCipherFilterBase<StreamCipherT>::m_cipher.decrypt(s, s, read);
return read;
}
};

And compress + encrypt ("out") & decrypt + uncompress ("in"):
(error checking removed for this post)

//
// Write out data compressing and encrypting as we go
//
boost::filesystem::ifstream inf(inFile.Get(), std::ios_base::binary |
std::ios_base::in);
boost::filesystem::ofstream outf(outFile.Get(), std::ios_base::binary |
std::ios_base::out);

StreamCipherEncryptFilter<CipherT> outCipherFilter(key);
boost::iostreams::filtering_ostreambuf out;
out.push(boost::iostreams::zlib_compressor()); // compress
out.push(outCipherFilter); // then encrypt
out.push(outf); // write to file

boost::iostreams::copy(inf, out);

//
// Write out decrypted and uncompressed data:
//
boost::filesystem::ifstream inf(inFile.Get(), std::ios_base::binary |
std::ios_base::in);
boost::filesystem::ofstream outf(outFile.Get(), std::ios_base::binary |
std::ios_base::out);

StreamCipherDecryptFilter<CipherT> inCipherFilter(key);
boost::iostreams::filtering_istreambuf in;
in.push(boost::iostreams::zlib_decompressor());
in.push(inCipherFilter);
in.push(inf);

boost::iostreams::copy(in, outf); // <--- exception is thrown here for many
files; some succeed with input md5 = output md5.

Can anyone help?

Bryan Ashby



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net