package crypto import ( "bytes" "crypto/rand" "path/filepath" "testing" ) func TestRoundTrip(t *testing.T) { t.Parallel() key := make([]byte, KeyLen) if _, err := rand.Read(key); err != nil { t.Fatalf("rand: %v", err) } a, err := NewAEAD(key) if err != nil { t.Fatalf("new: %v", err) } plaintext := []byte("super-secret-restic-password") ad := []byte("repos/01HJ8K7/password") ct, err := a.Encrypt(plaintext, ad) if err != nil { t.Fatalf("encrypt: %v", err) } if ct == "" { t.Fatal("ciphertext empty") } pt, err := a.Decrypt(ct, ad) if err != nil { t.Fatalf("decrypt: %v", err) } if !bytes.Equal(pt, plaintext) { t.Errorf("round-trip mismatch: got %q want %q", pt, plaintext) } } func TestADMismatchFails(t *testing.T) { t.Parallel() key := make([]byte, KeyLen) _, _ = rand.Read(key) a, _ := NewAEAD(key) ct, _ := a.Encrypt([]byte("secret"), []byte("context-A")) if _, err := a.Decrypt(ct, []byte("context-B")); err == nil { t.Fatal("expected AD-mismatch failure, got nil") } } func TestNonceUniqueness(t *testing.T) { t.Parallel() key := make([]byte, KeyLen) _, _ = rand.Read(key) a, _ := NewAEAD(key) // Same plaintext + AD must produce different ciphertexts because // we use a random nonce per call. If this ever fails the AEAD is // broken or someone made the nonce deterministic. ct1, _ := a.Encrypt([]byte("x"), nil) ct2, _ := a.Encrypt([]byte("x"), nil) if ct1 == ct2 { t.Fatal("two encryptions produced identical ciphertext — nonce reuse") } } func TestKeyFileLifecycle(t *testing.T) { t.Parallel() dir := t.TempDir() path := filepath.Join(dir, "secret.key") if err := GenerateKeyFile(path); err != nil { t.Fatalf("generate: %v", err) } // Refusal-to-overwrite is the safety property — a re-run of the // server must not silently swap the key. if err := GenerateKeyFile(path); err == nil { t.Fatal("expected refusal to overwrite, got nil") } key, err := LoadKeyFromFile(path) if err != nil { t.Fatalf("load: %v", err) } if len(key) != KeyLen { t.Errorf("key length: got %d want %d", len(key), KeyLen) } } func TestRejectShortKey(t *testing.T) { t.Parallel() if _, err := NewAEAD(make([]byte, KeyLen-1)); err == nil { t.Fatal("expected short-key rejection, got nil") } } func TestRejectShortCiphertext(t *testing.T) { t.Parallel() key := make([]byte, KeyLen) _, _ = rand.Read(key) a, _ := NewAEAD(key) if _, err := a.Decrypt("AAAA", nil); err == nil { t.Fatal("expected short-ciphertext rejection, got nil") } }