Skip to content
This repository has been archived by the owner on Apr 17, 2024. It is now read-only.

Go: Streaming AEAD decryption keeps a full copy of the stream's contents in memory #594

Closed
vonhollen opened this issue Mar 19, 2022 · 0 comments
Assignees

Comments

@vonhollen
Copy link

Describe the bug:

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.

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-L71

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.

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:

Top in-use heap objects:
#1 size=1023.05MiB objects=1
      bytes.makeSlice buffer.go:229
      bytes.(*Buffer).grow buffer.go:142
      bytes.(*Buffer).Write buffer.go:172
      io.(*teeReader).Read io.go:574
      io.ReadAtLeast io.go:331
      io.ReadFull io.go:350
      tink/go/streamingaead/subtle/noncebased/noncebased.(*Reader).Read tink/go/streamingaead/subtle/noncebased/noncebased.go:280
      tink/go/streamingaead/streamingaead.(*decryptReader).Read tink/go/streamingaead/decrypt_reader.go:46
      main.main streammemoryusage.go:70

Provide your version information:

  • Language: Go
  • Version:
  • Environment: Debian
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants