internal/stream: reject trailing data (no EOF) after end of stream

This commit is contained in:
Filippo Valsorda
2022-06-19 23:11:14 +02:00
parent 2e090545df
commit 3f56ac13fb
45 changed files with 526 additions and 29 deletions

View File

@@ -8,6 +8,7 @@ package stream
import (
"crypto/cipher"
"errors"
"fmt"
"io"
"golang.org/x/crypto/chacha20poly1305"
@@ -66,7 +67,17 @@ func (r *Reader) Read(p []byte) (int, error) {
r.unread = r.unread[n:]
if last {
r.err = io.EOF
// Ensure there is an EOF after the last chunk as expected. In other
// words, check for trailing data after a full-length final chunk.
// Hopefully, the underlying reader supports returning EOF even if it
// had previously returned an EOF to ReadFull.
if _, err := r.src.Read(make([]byte, 1)); err == nil {
r.err = errors.New("trailing data after end of encrypted file")
} else if err != io.EOF {
r.err = fmt.Errorf("non-EOF error reading after end of encrypted file: %w", err)
} else {
r.err = io.EOF
}
}
return n, nil

View File

@@ -9,6 +9,7 @@ import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"fmt"
"io"
"os"
@@ -30,6 +31,16 @@ var _, TestX25519Identity, _ = bech32.Decode(
var TestX25519Recipient, _ = curve25519.X25519(TestX25519Identity, curve25519.Basepoint)
// These are the file key and nonce used to encrypt any full/multiple-chunk
// tests. They were generated by a previous iteration of this test suite.
// Reusing them across files and history makes the repository easier to pack and
// the test suite easier to compress.
var LargeTestFileKey, _ = hex.DecodeString("7aa5bdac0e6afeed3dd0a7eccb42af44")
var LargeTestNonce, _ = hex.DecodeString("c82f71eb82029b77136399e485e879f4")
var LargeTestFirstChunk = bytes.Repeat([]byte{0}, 64*1024)
var LargeTestSecondChunk = bytes.Repeat([]byte{1}, 64*1024)
var LargeTestThirdChunk = bytes.Repeat([]byte{2}, 64*1024)
func NotCanonicalBase64(s string) string {
// Assuming there are spare zero bits at the end of the encoded bitstring,
// the character immediately after in the alphabet compared to the last one
@@ -222,6 +233,14 @@ func (f *TestFile) ExpectHeaderFailure() {
func (f *TestFile) ExpectPayloadFailure() {
f.expect = "payload failure"
f.payload.Reset()
}
func (f *TestFile) ExpectPartialPayload(goodBytes int) {
f.expect = "payload failure"
payload := f.payload.Bytes()
f.payload.Reset()
f.payload.Write(payload[:goodBytes])
}
func (f *TestFile) ExpectHMACFailure() {
@@ -238,7 +257,7 @@ func (f *TestFile) Comment(c string) {
func (f *TestFile) Generate() {
fmt.Printf("expect: %s\n", f.expect)
if f.expect == "success" {
if f.expect == "success" || f.expect == "payload failure" {
fmt.Printf("payload: %x\n", sha256.Sum256(f.payload.Bytes()))
}
fmt.Printf("file key: %x\n", f.fileKey)