Tink is a multi-language, cross-platform, open source library that provides cryptographic APIs that are secure, easy to use correctly, and hard(er) to misuse.
The reader returned by calling NewDecryptingReader(in) on the result of streamingaead.New(handle) keeps the entire contents of in in-memory until the reader is garbage collected.
That buffer makes it possible to rewind the stream and try another key if the first one fails, but the buffer isn't just used while finding the correct key. It's still referenced by the io.TeeReader implementation, so reading a 1GiB stream will allocate more than 1GiB of memory.
Going around streamingaead.New(handle) by turning the primary primitive into a tink.StreamingAEAD and calling NewDecryptingReader(...) on that works around the problem and the process consumes megabytes of memory instead of gigabytes on large streams.
What was the expected behavior?
Streaming AEAD memory usage during decryption should not increase linearly with the stream length.
One fix is to implement a reader that replaces the tee+buffer with a buffer that can be deactivated once the matching key is found.
Describe the bug:
The reader returned by calling
NewDecryptingReader(in)
on the result ofstreamingaead.New(handle)
keeps the entire contents ofin
in-memory until the reader is garbage collected.This happens because the ciphertext stream is tee'd to a buffer here, and that's what's passed to the primitive's real
NewDecryptionReader
implementation: https://github.com/google/tink/blob/645c17cbd121b9db7c6c336521c2c37717003332/go/streamingaead/decrypt_reader.go#L67-L71That buffer makes it possible to rewind the stream and try another key if the first one fails, but the buffer isn't just used while finding the correct key. It's still referenced by the
io.TeeReader
implementation, so reading a 1GiB stream will allocate more than 1GiB of memory.Going around
streamingaead.New(handle)
by turning the primary primitive into atink.StreamingAEAD
and callingNewDecryptingReader(...)
on that works around the problem and the process consumes megabytes of memory instead of gigabytes on large streams.What was the expected behavior?
Streaming AEAD memory usage during decryption should not increase linearly with the stream length.
One fix is to implement a reader that replaces the tee+buffer with a buffer that can be deactivated once the matching key is found.
How can we reproduce the bug?
Example of the problem and the workaround that shows ideal/expected memory usage: https://gist.github.com/vonhollen/64d51c56bd9d2294428da57a552ed457
Do you have any debugging information?
When running the example above, you'll see the tee'd buffer in the heap summary near the end:
Provide your version information: