RustCrypto / AEADs

Authenticated Encryption with Associated Data Algorithms: high-level encryption ciphers
672 stars 140 forks source link

Support for streaming AES-GCM encryption #556

Open MasterAwesome opened 8 months ago

MasterAwesome commented 8 months ago

I couldn't find an API to support streaming AES-GCM encryption. In a way such the the whole plaintext is sent in chunks and the tag needs to be computed for the entire plaintext.

The goal is to be able to generate partial ciphertexts in memory constrained environments. Is this doable? are there any security implications of this?

MasterAwesome commented 8 months ago

Ok I was able to implement a streaming version of GCM outside of this crate using it's primitives like ghash. When doing update calls with sizes multiples of block size the tag is generated correctly however when I'm streaming non multiples of block size it computes the wrong tag. My guess is because I'm using ghash.update_padded. Is the only way to buffer the partial blocks until it fills up the ghash block size?

tarcieri commented 8 months ago

We don't currently support a streaming encryption API for AEADs. If you'd like to propose one, https://github.com/rustcrypto/traits is probably the right place: we use trait-based APIs. There was some discussion of streaming specific to AAD here (and there's been past discussion of this elsewhere but I'd have to dig it up):

https://github.com/RustCrypto/traits/issues/62

As you've discovered, the buffering gets tricky. The rest of the AEAD implementations are designed to be one-shot, which simplifies implementing performant implementations. We have avoided working on streaming APIs like this largely because performance is not where we'd like it to be yet with the one-shot encryption APIs and trying to support streaming encryption just makes everything that much more complicated around all of the things required to make the performance of the one-shot APIs optimal (namely buffering/scheduling).

MasterAwesome commented 8 months ago

We don't currently support a streaming encryption API for AEADs. If you'd like to propose one, https://github.com/rustcrypto/traits is probably the right place: we use trait-based APIs. There was some discussion of streaming specific to AAD here (and there's been past discussion of this elsewhere but I'd have to dig it up):

https://github.com/RustCrypto/traits/issues/62

As you've discovered, the buffering gets tricky. The rest of the AEAD implementations are designed to be one-shot, which simplifies implementing performant implementations. We have avoided working on streaming APIs like this largely because performance is not where we'd like it to be yet with the one-shot encryption APIs and trying to support streaming encryption just makes everything that much more complicated around all of the things required to make the performance of the one-shot APIs optimal (namely buffering/scheduling).

This makes sense let me work on this a little more and get back to contributing. I have a working solution which buffers only one ghash block at the most, the key stream is always applied to the entire input (buffered CT is stored just for ghash future updates). NIST test vectors pass with different chunks of byte granular update calls, so I'm quite sure it works functionally, now to look at if side channels are introduced if I buffer it the way I am doing :)

It's been a really fun learning process though. I will definitely contribute back when I'm certain about the implementation for design ideas.

tarcieri commented 8 months ago

I opened https://github.com/RustCrypto/traits/issues/1364 to track a full incremental encryption API