Skip to content
Snippets Groups Projects
Commit fd83f03c authored by Karl Fogel's avatar Karl Fogel
Browse files

Fix digest bug of commit f90484e1 / commit c9095f8b

The bug was a digest miscalculation when encrypting, and its cause was
a confusion about the order in which different things would get hashed
into the digest.

The right order is that the raw head fuzz gets hashed first, followed
by all the message plaintext.  But a subtle problem could either cause
the plaintext hashing to never happen at all, or cause the order of
hashing to be reversed.

The generation of head fuzz was being done in the first call to
convert(), but commit c9095f8b changed PadEncoder.encode() so that
*both* its call to convert() and its call to digest_gulp() were
conditionalized on whether there was some compressed output ready to
encode.  Remember, the compressor doesn't always emit anything on a
given call -- if it can't do enough compression, it buffers stuff up
for a while in the hopes that future input will be compressible based
on past input.

Furthermore, on short input, *no* call to compressor.compress()
returns any output, and we have to wait until compressor.flush(),
which isn't called until PadEncoder.finish().  This means that either
digest_gulp() doesn't get called at all, or, conversely, if we
deconditionalize it in PadEncoder.encode(), it gets called *before*
the first call to convert() -- because convert() would now first be
called in PadEncoder.finish() instead of in PadEncoder.encode() --
thus reversing the order in which head fuzz and plaintext get hashed.

The solution is to do what we should have done a long time ago:
prepare head fuzz in PadSession.prepare_for_encryption(), so that
hashing isn't sensitive to the order of calls to convert().  (A
corollary is that decryption should probably work the same way, but
let's do one change at a time.)

This solution also preserves the fix of the bug that commit c9095f8b
fixed -- the ugly and information-leaking extra newline in the base64
output, between head fuzz section and the message section -- by
ensuring that we never call base64.encodestring() on empty input.

Most of 'make check' still passes after this, except that some tests
still fail as before because of zap expectation issues:

  ERROR: expected 'v', found 'z'
  ERROR: did not see expected DigestMismatch message digest error
  FAIL: tampering with message digest causes authentication error

  ERROR: expected 'a', found 'w'
  ERROR: did not see expected DigestMismatch head fuzz digest error
  FAIL: tampering with head fuzz digest causes authentication error

I will finish updating the test suite in a subsequent commit.

* onetime
  (PadSession.__init__): New internal var self._head_buffer.
  (PadSession.prepare_for_encryption): Fill _head_buffer.
  (PadSession.convert): Don't handle head fuzz here, just prepend any
    head buffer to the result and empty the head buffer if so.  Also,
    add a blank line to indicate conditional flow better, and remove
    an obsolete comment.
  (PadSession._get_id): Remove extra blank line before definition start.
  (PadSession._consume_fuzz_bytes): Fix test for is_head_fuzz.
  (PadSession._make_fuzz): Fix doc string, and remove obsolete comment.
  (SessionEncoder.__init__): Remove _started_encoding flag.
  (SessionEncoder.encode): Deconditionalize call to digest_gulp.
parent f90484e1
No related branches found
No related tags found
No related merge requests found
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment