Skip to content

Commit 9a14052

Browse files
committed
age: compress large test files
1 parent 29c5a43 commit 9a14052

37 files changed

+99
-95
lines changed

age/README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ processed independently. Each vector is meant to test only one failure (or
5151
success) scenario.
5252

5353
The file is in two parts: first a textual header, then an empty line, and then
54-
an age encrypted file. The textual header is a series of key-value pairs,
55-
separated by a colon and a space, each on their own line.
54+
an age encrypted file, possibly compressed. The textual header is a series of
55+
key-value pairs, separated by a colon and a space, each on their own line.
5656

5757
The following header keys are defined. Files with unknown keys should be
5858
ignored.
@@ -97,6 +97,13 @@ ignored.
9797

9898
The ASCII armor should fail to parse successfully.
9999

100+
- `compressed`
101+
102+
This key will be `gzip` if the age encrypted file is compressed with gzip.
103+
Note that encrypted files usually don't compress well, but large test files in
104+
this collection are generated from plaintexts selected to make the ciphertext
105+
compressible. **Some of these files can be several megabytes once decompressed.**
106+
100107
- `payload`
101108

102109
This is a hex-encoded SHA-256 hash of the payload. **All** the plaintext that

age/internal/testkit/testkit.go

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ package testkit
66

77
import (
88
"bytes"
9+
"compress/zlib"
910
"crypto/hmac"
1011
"crypto/sha256"
1112
"encoding/base64"
12-
"encoding/hex"
1313
"fmt"
1414
"io"
1515
"os"
@@ -31,15 +31,7 @@ var _, TestX25519Identity, _ = bech32.Decode(
3131

3232
var TestX25519Recipient, _ = curve25519.X25519(TestX25519Identity, curve25519.Basepoint)
3333

34-
// These are the file key and nonce used to encrypt any full/multiple-chunk
35-
// tests. They were generated by a previous iteration of this test suite.
36-
// Reusing them across files and history makes the repository easier to pack and
37-
// the test suite easier to compress.
38-
var LargeTestFileKey, _ = hex.DecodeString("7aa5bdac0e6afeed3dd0a7eccb42af44")
39-
var LargeTestNonce, _ = hex.DecodeString("c82f71eb82029b77136399e485e879f4")
40-
var LargeTestFirstChunk = bytes.Repeat([]byte{0}, 64*1024)
41-
var LargeTestSecondChunk = bytes.Repeat([]byte{1}, 64*1024)
42-
var LargeTestThirdChunk = bytes.Repeat([]byte{2}, 64*1024)
34+
const ChunkSize = 64 * 1024
4335

4436
func NotCanonicalBase64(s string) string {
4537
// Assuming there are spare zero bits at the end of the encoded bitstring,
@@ -213,29 +205,43 @@ func (f *TestFile) HMAC() {
213205
f.HMACLine(h.Sum(nil))
214206
}
215207

216-
func (f *TestFile) Nonce(nonce []byte) {
208+
func (f *TestFile) Nonce() {
209+
nonce := f.Rand(16)
217210
f.streamKey = make([]byte, 32)
218211
hkdf.New(sha256.New, f.fileKey, nonce, []byte("payload")).Read(f.streamKey)
219212
f.Buf.Write(nonce)
220213
}
221214

222-
func (f *TestFile) PayloadChunk(plaintext []byte) {
215+
func (f *TestFile) PayloadChunk(size int) {
216+
plaintext := bytes.Repeat([]byte{0}, size)
217+
s, _ := chacha20.NewUnauthenticatedCipher(f.streamKey, f.nonce[:])
218+
s.SetCounter(1)
219+
s.XORKeyStream(plaintext, plaintext)
220+
f.payloadChunk(plaintext)
221+
}
222+
223+
func (f *TestFile) payloadChunk(plaintext []byte) {
223224
f.payload.Write(plaintext)
224225
aead, _ := chacha20poly1305.New(f.streamKey)
225226
f.Buf.Write(aead.Seal(nil, f.nonce[:], plaintext, nil))
226-
f.nonce[10]++
227+
228+
for i := 10; i >= 0; i-- {
229+
f.nonce[i]++
230+
if f.nonce[i] != 0 {
231+
break
232+
}
233+
}
227234
}
228235

229-
func (f *TestFile) PayloadChunkFinal(plaintext []byte) {
230-
f.payload.Write(plaintext)
236+
func (f *TestFile) PayloadChunkFinal(size int) {
231237
f.nonce[11] = 1
232-
aead, _ := chacha20poly1305.New(f.streamKey)
233-
f.Buf.Write(aead.Seal(nil, f.nonce[:], plaintext, nil))
238+
f.PayloadChunk(size)
234239
}
235240

236241
func (f *TestFile) Payload(plaintext string) {
237-
f.Nonce(f.Rand(16))
238-
f.PayloadChunkFinal([]byte(plaintext))
242+
f.Nonce()
243+
f.nonce[11] = 1
244+
f.payloadChunk([]byte(plaintext))
239245
}
240246

241247
func (f *TestFile) ExpectHeaderFailure() {
@@ -305,6 +311,12 @@ func (f *TestFile) Generate() {
305311
if f.comment != "" {
306312
fmt.Printf("comment: %s\n", f.comment)
307313
}
314+
out := io.Writer(os.Stdout)
315+
if f.Buf.Len() > 1024 {
316+
fmt.Printf("compressed: zlib\n")
317+
out, _ = zlib.NewWriterLevel(os.Stdout, zlib.BestCompression)
318+
defer out.(*zlib.Writer).Close()
319+
}
308320
fmt.Println()
309-
io.Copy(os.Stdout, &f.Buf)
321+
io.Copy(out, &f.Buf)
310322
}

age/internal/tests/armor_garbage_encoded.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,13 @@ import "c2sp.org/CCTV/age/internal/testkit"
1111

1212
func main() {
1313
f := testkit.NewTestFile()
14-
f.FileKey(testkit.LargeTestFileKey)
1514
f.VersionLine("v1")
1615
f.X25519(testkit.TestX25519Identity)
1716
f.HMAC()
18-
f.Nonce(testkit.LargeTestNonce)
19-
f.PayloadChunkFinal(testkit.LargeTestFirstChunk)
17+
f.Nonce()
18+
f.PayloadChunkFinal(testkit.ChunkSize)
2019
f.Buf.Write(f.Rand(20))
21-
f.ExpectPartialPayload(64 * 1024)
20+
f.ExpectPartialPayload(testkit.ChunkSize)
2221
file := f.Bytes()
2322
f.Buf.Reset()
2423
f.BeginArmor("AGE ENCRYPTED FILE")

age/internal/tests/stream_bad_tag_second_chunk.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,16 @@ import "c2sp.org/CCTV/age/internal/testkit"
1111

1212
func main() {
1313
f := testkit.NewTestFile()
14-
f.FileKey(testkit.LargeTestFileKey)
1514
f.VersionLine("v1")
1615
f.X25519(testkit.TestX25519Identity)
1716
f.HMAC()
18-
f.Nonce(testkit.LargeTestNonce)
19-
f.PayloadChunk(testkit.LargeTestFirstChunk)
20-
f.PayloadChunkFinal([]byte("age"))
17+
f.Nonce()
18+
f.PayloadChunk(testkit.ChunkSize)
19+
f.PayloadChunkFinal(1)
2120
file := f.Buf.Bytes()
2221
f.Buf.Reset()
2322
file[len(file)-1] ^= 0b0010_0000
2423
f.Buf.Write(file)
25-
f.ExpectPartialPayload(64 * 1024)
24+
f.ExpectPartialPayload(testkit.ChunkSize)
2625
f.Generate()
2726
}

age/internal/tests/stream_bad_tag_second_chunk_full.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,16 @@ import "c2sp.org/CCTV/age/internal/testkit"
1111

1212
func main() {
1313
f := testkit.NewTestFile()
14-
f.FileKey(testkit.LargeTestFileKey)
1514
f.VersionLine("v1")
1615
f.X25519(testkit.TestX25519Identity)
1716
f.HMAC()
18-
f.Nonce(testkit.LargeTestNonce)
19-
f.PayloadChunk(testkit.LargeTestFirstChunk)
20-
f.PayloadChunkFinal(testkit.LargeTestSecondChunk)
17+
f.Nonce()
18+
f.PayloadChunk(testkit.ChunkSize)
19+
f.PayloadChunkFinal(testkit.ChunkSize)
2120
file := f.Buf.Bytes()
2221
f.Buf.Reset()
2322
file[len(file)-1] ^= 0b0010_0000
2423
f.Buf.Write(file)
25-
f.ExpectPartialPayload(64 * 1024)
24+
f.ExpectPartialPayload(testkit.ChunkSize)
2625
f.Generate()
2726
}

age/internal/tests/stream_last_chunk_empty.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,13 @@ import "c2sp.org/CCTV/age/internal/testkit"
1111

1212
func main() {
1313
f := testkit.NewTestFile()
14-
f.FileKey(testkit.LargeTestFileKey)
1514
f.VersionLine("v1")
1615
f.X25519(testkit.TestX25519Identity)
1716
f.HMAC()
18-
f.Nonce(testkit.LargeTestNonce)
19-
f.PayloadChunk(testkit.LargeTestFirstChunk)
20-
f.PayloadChunkFinal([]byte{})
17+
f.Nonce()
18+
f.PayloadChunk(testkit.ChunkSize)
19+
f.PayloadChunkFinal(0)
2120
f.Comment("final STREAM chunk can't be empty unless whole payload is empty")
22-
f.ExpectPartialPayload(64 * 1024)
21+
f.ExpectPartialPayload(testkit.ChunkSize)
2322
f.Generate()
2423
}

age/internal/tests/stream_last_chunk_full.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@ import "c2sp.org/CCTV/age/internal/testkit"
1111

1212
func main() {
1313
f := testkit.NewTestFile()
14-
f.FileKey(testkit.LargeTestFileKey)
1514
f.VersionLine("v1")
1615
f.X25519(testkit.TestX25519Identity)
1716
f.HMAC()
18-
f.Nonce(testkit.LargeTestNonce)
19-
f.PayloadChunkFinal(testkit.LargeTestFirstChunk)
17+
f.Nonce()
18+
f.PayloadChunkFinal(testkit.ChunkSize)
2019
f.Generate()
2120
}

age/internal/tests/stream_last_chunk_full_second.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,11 @@ import "c2sp.org/CCTV/age/internal/testkit"
1111

1212
func main() {
1313
f := testkit.NewTestFile()
14-
f.FileKey(testkit.LargeTestFileKey)
1514
f.VersionLine("v1")
1615
f.X25519(testkit.TestX25519Identity)
1716
f.HMAC()
18-
f.Nonce(testkit.LargeTestNonce)
19-
f.PayloadChunk(testkit.LargeTestFirstChunk)
20-
f.PayloadChunkFinal(testkit.LargeTestSecondChunk)
17+
f.Nonce()
18+
f.PayloadChunk(testkit.ChunkSize)
19+
f.PayloadChunkFinal(testkit.ChunkSize)
2120
f.Generate()
2221
}

age/internal/tests/stream_no_chunks.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ func main() {
1414
f.VersionLine("v1")
1515
f.X25519(testkit.TestX25519Recipient)
1616
f.HMAC()
17-
f.Nonce(f.Rand(16))
17+
f.Nonce()
1818
f.ExpectPayloadFailure()
1919
f.Generate()
2020
}

age/internal/tests/stream_no_final.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ func main() {
1414
f.VersionLine("v1")
1515
f.X25519(testkit.TestX25519Recipient)
1616
f.HMAC()
17-
f.Nonce(f.Rand(16))
18-
f.PayloadChunk([]byte("age"))
17+
f.Nonce()
18+
f.PayloadChunk(1)
1919
f.ExpectPayloadFailure()
2020
f.Generate()
2121
}

0 commit comments

Comments
 (0)