|
From: Shawn W. <swi...@go...> - 2011-03-22 22:42:39
|
I stumbled across a bug, and found a solution to it. I realize this
project is dead, and that everyone should be migrating away from it,
but some of us are stuck (at least for a little longer) with legacy
code which uses it. I realize there won't be any more releases, but I
though I might as well post the problem and the fix for anyone else
who finds themselves in the same boat.
One manifestation of this bug is that when you use the streaming PGP
decryption API (DecodedMessageInputStream) to decrypt a signed stream,
you get a PGPFatalDataFormatException with the message "Read tried
past end of inputstream". The stack trace looks like:
cryptix.openpgp.PGPFatalDataFormatException: Read tried past end of inputstream.
at cryptix.openpgp.io.PGPLengthDataInputStream.readDirect(PGPLengthDataInputStream.java:123)
at cryptix.openpgp.io.PGPLengthDataInputStream.readInternal(PGPLengthDataInputStream.java:159)
at cryptix.openpgp.io.PGPLengthDataInputStream.readBuffer(PGPLengthDataInputStream.java:286)
at cryptix.openpgp.io.PGPLengthDataInputStream.readBuffer(PGPLengthDataInputStream.java:250)
at cryptix.openpgp.io.PGPLengthDataInputStream.readByteArray(PGPLengthDataInputStream.java:320)
at cryptix.openpgp.packet.PGPSignaturePacket.decodeBody(PGPSignaturePacket.java:507)
at cryptix.openpgp.provider.PGPDecodedMessageInputStream$SignedLiteralInputStream.verify(PGPDecodedMessageInputStream.java:732)
at cryptix.openpgp.provider.PGPDecodedMessageInputStream.engineClose(PGPDecodedMessageInputStream.java:485)
at cryptix.message.stream.DecodedMessageInputStream.close(DecodedMessageInputStream.java:162)
at com.google.math.crypto.pgp.cryptix.CryptixDecryptionStream.close(CryptixDecryptionStream.java:70)
at com.google.math.crypto.pgp.cryptix.CryptixDecryptionStream.read(CryptixDecryptionStream.java:53)
The problem actually lies in
cryptix.openpgp.provider.PGPDecodedMessageInputStream.read(byte[],int,int),
on line 905. The troublesome code is:
if ((in.available() == 0) && (buf.length - bufoffset == 0))
return 0;
This basically says "if the underlying stream (which contains
encrypted data) says it has no more data available and if our own
buffer (containing already-decrypted data) is empty, then return 0
indicating that we have no more decrypted data to be read.
Unfortunately, this test misses a third source of data -- the cipher
object. It may have some additional data which will be returned by
the call to doFinal(). If this is the case, the above lines ensure
that the reader never gets that additional data.
To fix the problem, simply delete the above two lines. This
quick-escape test is actually unnecessary, since the following code
works just fine even when no data is available from the underlying
stream or in the data buffer. And without the quick-escape, the code
recognizes the end-of-stream condition and calls doFinal() on the
cipher, allowing it to retrieve and return the last of the decrypted
data.
A patch file is attached.
--
Shawn Willden
swi...@go...
|