Initial vault: single-binary post-quantum file vault
Strip Fury back to its vault functionality in one `vault` command: genkey, init, add (file or directory, optional folder inside the vault), list, get, mv and rm. The hybrid FrodoKEM-640 + ML-KEM-768 encryption core is kept under internal/pqcrypt. Signing, policies, profiles, backups, SSH remotes, FIDO2, agents, provenance and compression are removed.
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package format_test
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/andydixon/vault/internal/format"
|
||||
)
|
||||
|
||||
func TestStanzaMarshal(t *testing.T) {
|
||||
s := &format.Stanza{
|
||||
Type: "test",
|
||||
Args: []string{"1", "2", "3"},
|
||||
Body: nil, // empty
|
||||
}
|
||||
buf := &bytes.Buffer{}
|
||||
s.Marshal(buf)
|
||||
if exp := "-> test 1 2 3\n\n"; buf.String() != exp {
|
||||
t.Errorf("wrong empty stanza encoding: expected %q, got %q", exp, buf.String())
|
||||
}
|
||||
|
||||
buf.Reset()
|
||||
s.Body = []byte("AAA")
|
||||
s.Marshal(buf)
|
||||
if exp := "-> test 1 2 3\nQUFB\n"; buf.String() != exp {
|
||||
t.Errorf("wrong normal stanza encoding: expected %q, got %q", exp, buf.String())
|
||||
}
|
||||
|
||||
buf.Reset()
|
||||
s.Body = bytes.Repeat([]byte("A"), format.BytesPerLine)
|
||||
s.Marshal(buf)
|
||||
if exp := "-> test 1 2 3\nQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFB\n\n"; buf.String() != exp {
|
||||
t.Errorf("wrong 64 columns stanza encoding: expected %q, got %q", exp, buf.String())
|
||||
}
|
||||
}
|
||||
|
||||
func FuzzMalleability(f *testing.F) {
|
||||
f.Fuzz(func(t *testing.T, data []byte) {
|
||||
h, payload, err := format.Parse(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
if h != nil {
|
||||
t.Error("h != nil on error")
|
||||
}
|
||||
if payload != nil {
|
||||
t.Error("payload != nil on error")
|
||||
}
|
||||
t.Skip()
|
||||
}
|
||||
w := &bytes.Buffer{}
|
||||
if err := h.Marshal(w); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := io.Copy(w, payload); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(w.Bytes(), data) {
|
||||
t.Error("Marshal output different from input")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// FuzzStanza exercises the recipient-stanza reader directly. Parse reaches it
|
||||
// only through a well-formed intro line, so fuzzing it on its own covers
|
||||
// stanza shapes a whole-file seed cannot easily reach.
|
||||
func FuzzStanza(f *testing.F) {
|
||||
f.Fuzz(func(t *testing.T, data []byte) {
|
||||
reader := format.NewStanzaReader(bufio.NewReader(bytes.NewReader(data)))
|
||||
for range 64 {
|
||||
stanza, err := reader.ReadStanza()
|
||||
if err != nil {
|
||||
if stanza != nil {
|
||||
t.Fatal("stanza returned alongside an error")
|
||||
}
|
||||
return
|
||||
}
|
||||
if stanza == nil {
|
||||
t.Fatal("no stanza and no error")
|
||||
}
|
||||
// Parser limits must hold: nothing an attacker supplies may make
|
||||
// the reader materialise more than the stanza size limit.
|
||||
if len(stanza.Body) > format.MaxStanzaSize {
|
||||
t.Fatalf("stanza body of %d bytes exceeds the %d byte limit", len(stanza.Body), format.MaxStanzaSize)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user