package capsule import ( "bytes" "errors" "testing" "filippo.io/age" datekeys "g.activething.com/go/DateKeys" ) // decryptAll reads the plaintext into one buffer of the ciphertext's size, so // that no outgrown buffer keeps a copy of I_PAYLOAD, and still reports a // truncated STREAM, which the age reader signals with io.ErrUnexpectedEOF. func TestDecryptAll(t *testing.T) { id, err := age.GenerateX25519Identity() if err != nil { t.Fatal(err) } const chunk = 64 << 10 for _, size := range []int{0, 1, 511, 512, 513, chunk, chunk + 1, 2*chunk + 100} { plaintext := bytes.Repeat([]byte{0xab}, size) ct, err := encryptAll(plaintext, id.Recipient()) if err != nil { t.Fatal(err) } out, err := decryptAll(ct, id) if err != nil || !bytes.Equal(out, plaintext) { t.Fatalf("%d bytes: %v", size, err) } if cap(out) != len(ct) { t.Errorf("%d bytes: a buffer of %d bytes for a ciphertext of %d", size, cap(out), len(ct)) } if size == 0 { continue } // The last chunk removed: a truncation at a chunk boundary. last := size % chunk if last == 0 { last = chunk } for _, cut := range []int{len(ct) - 1, len(ct) - (last + 16)} { if _, err := decryptAll(ct[:cut], id); !errors.Is(err, datekeys.ErrIntegrity) { t.Errorf("%d bytes cut to %d of %d: %v", size, cut, len(ct), err) } } } }