The application has no way to limit the header separately from the body,
so we have to enforce some sanity limits to prevent excessive memory use.
To relax the limits somewhat, make the parsing more efficient.
New limits are:
* 2 MiB total header size (enough for > 1024 PQ recipients)
* 1024 recipient stanzas
* 128 arguments per stanza
Fixes#701
The trailing data check after a full-length final chunk ignored the
byte count, so a reader returning (1, io.EOF), as io.Reader permits,
would have its trailing data silently accepted, and a transient
(0, nil) return would be misreported as trailing data. io.ReadFull
handles both.
trackReader.Read panicked if called again after a read returned io.EOF,
which can happen with readers that do not return EOF consistently, such
as a terminal after Ctrl-D. Latch the EOF instead, per the io.Reader
contract, so count stays consistent with the file size.
Fixes#719
Co-authored-by: Filippo Valsorda <hi@filippo.io>
Replace two hand-rolled slicesEqual helpers with slices.Equal from
the standard library, which is already imported in age.go.
(age.go:211-221, plugin/plugin.go:666-676)
Fix godoc link typo [Indentity] -> [Identity].
(plugin/plugin.go:3)
Fix comment typo "not MinPayload" -> "so MinPayload".
(internal/inspect/inspect.go:25)
Co-authored-by: Claude <noreply@anthropic.com>
If the implementation re-encodes the header before checking the HMAC,
that would mask malleability issues: the HMAC check would fail because
the tests HMAC'd the original header, but an attacker could also produce
the right HMAC. Instead of duplicating every parsing tests (with the
original and re-encoded HMAC), we make the test framework distinguish
HMAC errors, which ensures bad encodings are recognized as such and not
bypassable HMAC errors.
A non-empty payload of length a multiple of the chunk size can be
encrypted in two ways: with the last chunk full, or with an extra empty
last chunk. This is mostly an oversight in the original spec.
Both age and rage generate full last chunks, so we should be still in
time to pick one of the two, and avoid the underspecification. It's not
the one I would have picked originally, maybe, because disallowing full
last chunks would have avoided the trial decryption, but oh well.