
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