mirror of
https://github.com/FiloSottile/age.git
synced 2025-12-23 05:25:14 +00:00
internal/stream: disallow empty final chunks
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.
This commit is contained in:
@@ -87,7 +87,11 @@ func (r *Reader) readChunk() (last bool, err error) {
|
||||
// A message can't end without a marked chunk. This message is truncated.
|
||||
return false, io.ErrUnexpectedEOF
|
||||
case err == io.ErrUnexpectedEOF:
|
||||
// The last chunk can be short.
|
||||
// The last chunk can be short, but not empty unless it's the first and
|
||||
// only chunk.
|
||||
if !nonceIsZero(&r.nonce) && n == r.a.Overhead() {
|
||||
return false, errors.New("last chunk is empty, try age v1.0.0, and please consider reporting this")
|
||||
}
|
||||
in = in[:n]
|
||||
last = true
|
||||
setLastChunkFlag(&r.nonce)
|
||||
@@ -128,6 +132,10 @@ func setLastChunkFlag(nonce *[chacha20poly1305.NonceSize]byte) {
|
||||
nonce[len(nonce)-1] = lastChunkFlag
|
||||
}
|
||||
|
||||
func nonceIsZero(nonce *[chacha20poly1305.NonceSize]byte) bool {
|
||||
return *nonce == [chacha20poly1305.NonceSize]byte{}
|
||||
}
|
||||
|
||||
type Writer struct {
|
||||
a cipher.AEAD
|
||||
dst io.Writer
|
||||
|
||||
Reference in New Issue
Block a user