Iostreams with two filters throws exception
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
On 08/08/2013 06:37, NuSkooler wrote:
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:
...
Can anyone help?
Bryan Ashby
Bryan, You are a lot more likely to get a response if you post a complete example. Just a single file with a main() would make it a lot easier to help you. You're not far from that with the code you posted. Have you tried catching the exception and extracting any information? Have you tried getting your debugger to stop on throw? Ken Appleby Soft Optics Ltd.
The exception that is thrown is a boost::iostreams::zlib_error. The error code that's found within is -3 which is defined as Z_DATA_ERROR. Here is another bit: If I remove the zlib compressor/decompressor (leaving only the encrypt/decrypt) and step through it looks like everything is working fine until the last buffer the decryption routine sees -- which it is unable to decrypt back to plain text. Stepping through the encryption routine seems OK to me though (it appears to properly encrypt everything OK). Note again that I can do the reverse: Remove the encrypt/decrypt but keep the compress/decompress and it works fine. ------------------------------
Message: 6 Date: Sat, 10 Aug 2013 10:11:18 -0500 From: Larry Evans
To: boost-users@lists.boost.org Subject: Re: [Boost-users] Iostreams with two filters throws exception (Ken Appleby) Message-ID: Content-Type: text/plain; charset=ISO-8859-1 Hi Bryan,
Could you please report what happened when you tried Ken's suggestions about either catching the exception or using a debugger to narrow down the cause of the problem?
-regards, Larry
participants (2)
-
Ken Appleby
-
NuSkooler