CryptoInputStream implements istream, but changes the behavior of istream in at least 2 ways:
1) Input failure throws an exception instead of setting failbit
2) No state flags are updated
A result of this is that CryptoInputStream::eof() always returns false.
The CryptoInputStream constructor uses the istream(streambuf * sb) constructor, which calls ios::init(streambuf* sb). The stream buffer is set to sb, but the state flags are set to default values. Which means the state flags for the in CryptoInputStream are different than the state flags of the input stream CryptoStreamBuf::_pIstr. The CryptoInputStream state flags are never updated, so they do not change from default.
As a workaround the original istream will update its state flags, which can be used to detect eof().
I don't have time to come up with a fix, but I did create a quick test case (attached).