Go · 3755 bytes Raw Blame History
1 // SPDX-License-Identifier: AGPL-3.0-or-later
2
3 package sealbox_test
4
5 import (
6 "crypto/rand"
7 "encoding/base64"
8 "errors"
9 "testing"
10
11 "golang.org/x/crypto/nacl/box"
12
13 "github.com/tenseleyFlow/shithub/internal/auth/sealbox"
14 )
15
16 func TestNewAndOpenAnonymous_RoundTrip(t *testing.T) {
17 b, err := sealbox.New()
18 if err != nil {
19 t.Fatalf("New: %v", err)
20 }
21 if b.PublicKeyBase64() == "" {
22 t.Fatal("empty public key")
23 }
24 pubKey := b.PublicKey()
25
26 plaintext := []byte("super-secret-value")
27 ciphertext, err := box.SealAnonymous(nil, plaintext, &pubKey, rand.Reader)
28 if err != nil {
29 t.Fatalf("SealAnonymous: %v", err)
30 }
31 encrypted := base64.StdEncoding.EncodeToString(ciphertext)
32
33 out, err := b.OpenAnonymous(encrypted)
34 if err != nil {
35 t.Fatalf("OpenAnonymous: %v", err)
36 }
37 if string(out) != string(plaintext) {
38 t.Errorf("round-trip: got %q, want %q", out, plaintext)
39 }
40 }
41
42 func TestFromBase64_DerivesPublicKeyConsistently(t *testing.T) {
43 // Encrypt against a known keypair, then verify FromBase64 yields
44 // a Box whose public key matches and which can decrypt.
45 original, err := sealbox.New()
46 if err != nil {
47 t.Fatalf("New: %v", err)
48 }
49 pubKey := original.PublicKey()
50 plaintext := []byte("hello")
51 ct, _ := box.SealAnonymous(nil, plaintext, &pubKey, rand.Reader)
52
53 // Round-trip via a new Box loaded from the original's private key.
54 // We need access to the private key — for tests, dump it via a
55 // secondary path: re-construct from a known fixed private key.
56 priv32 := make([]byte, 32)
57 priv32[0] = 1 // deterministic non-zero scalar
58 loaded, err := sealbox.FromBase64(base64.StdEncoding.EncodeToString(priv32))
59 if err != nil {
60 t.Fatalf("FromBase64: %v", err)
61 }
62 loadedPub := loaded.PublicKey()
63 pt := []byte("via-fromb64")
64 ct2, _ := box.SealAnonymous(nil, pt, &loadedPub, rand.Reader)
65 out, err := loaded.OpenAnonymous(base64.StdEncoding.EncodeToString(ct2))
66 if err != nil {
67 t.Fatalf("OpenAnonymous loaded: %v", err)
68 }
69 if string(out) != string(pt) {
70 t.Errorf("loaded round-trip: got %q, want %q", out, pt)
71 }
72 // And confirm the unrelated keypair's ciphertext can't open here.
73 _, err = loaded.OpenAnonymous(base64.StdEncoding.EncodeToString(ct))
74 if !errors.Is(err, sealbox.ErrDecryptFailed) {
75 t.Errorf("expected ErrDecryptFailed for foreign ciphertext; got %v", err)
76 }
77 }
78
79 func TestFromBase64_RejectsBadInput(t *testing.T) {
80 cases := []string{
81 "",
82 "!!!not-base64!!!",
83 base64.StdEncoding.EncodeToString([]byte("too-short")),
84 }
85 for _, in := range cases {
86 if _, err := sealbox.FromBase64(in); !errors.Is(err, sealbox.ErrInvalidPrivateKey) {
87 t.Errorf("FromBase64(%q): got %v, want ErrInvalidPrivateKey", in, err)
88 }
89 }
90 }
91
92 func TestOpenAnonymous_RejectsMalformed(t *testing.T) {
93 b, err := sealbox.New()
94 if err != nil {
95 t.Fatalf("New: %v", err)
96 }
97 if _, err := b.OpenAnonymous("not-base64!@#"); !errors.Is(err, sealbox.ErrCiphertextMalformed) {
98 t.Errorf("malformed base64: got %v, want ErrCiphertextMalformed", err)
99 }
100 if _, err := b.OpenAnonymous(base64.StdEncoding.EncodeToString([]byte("too-short"))); !errors.Is(err, sealbox.ErrDecryptFailed) {
101 t.Errorf("too-short ciphertext: got %v, want ErrDecryptFailed", err)
102 }
103 }
104
105 func TestKeyID_StableForFixedKey(t *testing.T) {
106 priv32 := make([]byte, 32)
107 priv32[0] = 7
108 b1, err := sealbox.FromBase64(base64.StdEncoding.EncodeToString(priv32))
109 if err != nil {
110 t.Fatalf("FromBase64: %v", err)
111 }
112 b2, err := sealbox.FromBase64(base64.StdEncoding.EncodeToString(priv32))
113 if err != nil {
114 t.Fatalf("FromBase64: %v", err)
115 }
116 if b1.KeyID() != b2.KeyID() {
117 t.Errorf("KeyID not stable: %q vs %q", b1.KeyID(), b2.KeyID())
118 }
119 if b1.KeyID() == "" || len(b1.KeyID()) != 16 {
120 t.Errorf("KeyID shape: got %q (len=%d)", b1.KeyID(), len(b1.KeyID()))
121 }
122 }
123