Skip to content

Streaming Interface for authenticated encryption? #218

@LoupVaillant

Description

@LoupVaillant

Now that Monocypher is just under 1900 lines of code, we have room for more functionality. One that is very tempting to add is streaming AEAD, similar to Libsodium's.

One reason for the temptation is the ability to share code with crypto_lock() and crypto_unlock(). If the streaming API is provided separately, then a bunch of code, most notably authentication, must be duplicated. Inside Monocypher however, we can define the current AEAD interface in terms of the streaming API. I have written a prototype that currently costs 49 lines of code (and 6 new functions, and one additional struct).

On the other hand, we don't want to include something of limited value. We may want other functionality in the future, and it would be a pity if we had to break the 2KLoC psychological barrier to get it. To be included, this streaming interface should satisfy the following criteria:

  • No major footguns.
  • Close enough to ideal for file encryption.
  • Close enough to ideal for interactive sessions over TCP (or other reliable ordered channel).

If possible, it should also satisfy those bonus criteria:

  • RFC 8439 friendly: Implementing with IETF's ChaCha20 (96-bit nonce, 32-bit counter) should be straightforward.
  • DJB friendly: Implementing it with the original ChaCha20 (64-bit nonce, 64-bit counter) should be straightforward.
  • Fast: we should limit unneeded overhead.
  • Compatible with crypto_lock() (mostly for the sake of elegance).
  • Able to handle unreasonably large chunks without triggering nonce reuse. (Though, who uses large chunks with a streaming API?)

One major question remains about the "no major footguns" criterion: key commitment. As they stand, polynomial hash based ciphers are vulnerable to attacks where the same message could be successfully decrypted under several possible keys. And most importantly, an attacker could find those keys and exploit that for nefarious purposes. There's also a related question about message commitment, where it's possible to find several messages that produce the same authentication tag (that requires knowledge of the key).

We could solve those problems by using a random key robust AEAD, such as Chacha20/Blake2b, or by adding a bunch of encrypted zeroes to the message (well, to each chunk, actually). This is either slower or unwieldy, not to mention the increased size overhead.

I believe there is another way: make sure the protocol leaves no room for tricking the recipient into using the wrong decryption key. Commit the key once, then use ordinary AEAD. Also, we need to determine how much of an issue the lack of message commitment may be.

If this works, then a ChaPoly based streaming interface is probably worth adding. If it does not work, then even crypto_lock() was probably not worth adding, and we'd better not compound the problem with yet another broken construction.

Food for thought, to be considered when we can make the time.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions