oficina / home Public

Clone
git clone https://amadan.net/oficina/home

Plain git — no account needed to clone.

Download

Download this file

1package seal
2
3import (
4 "bytes"
5 "crypto/aes"
6 "crypto/cipher"
7 "encoding/hex"
8 "sync"
9 "testing"
10)
11
12func testKey() []byte {
13 b := make([]byte, 32)
14 for i := range b {
15 b[i] = byte(i)
16 }
17 return b
18}
19
20// These derivation vectors predate extraction, from Home's deployed sealer.
21func TestHistoricalHomeVectors(t *testing.T) {
22 s, err := New(testKey(), "oficina/home")
23 if err != nil {
24 t.Fatal(err)
25 }
26 for purpose, want := range map[string]string{"signin.address": "1c677fc03245425f809a5a8ba5fda280f745ee96babd14ac8a75857ec9c7fe00", "team.name": "8cadd5d2a5921541918563b0046844c371de29743a4b9335759da8c345bfc732", "queue.payload": "2d6b4e963b93489c6a9515469f274516e48014d0bdb01831a9ff65086d0cb999"} {
27 key, err := s.purposeKey(purpose)
28 if err != nil || hex.EncodeToString(key) != want {
29 t.Fatal("historical key changed", purpose, err)
30 }
31 block, err := aes.NewCipher(key)
32 if err != nil {
33 t.Fatal(err)
34 }
35 aead, err := cipher.NewGCM(block)
36 if err != nil {
37 t.Fatal(err)
38 }
39 nonce := bytes.Repeat([]byte{0x5a}, aead.NonceSize())
40 plaintext := []byte("historical fixture")
41 old := aead.Seal(append([]byte(nil), nonce...), nonce, plaintext, nil)
42 got, err := s.Open(purpose, old)
43 if err != nil || !bytes.Equal(got, plaintext) {
44 t.Fatal("old envelope unreadable", err)
45 }
46 current, err := s.Seal(purpose, plaintext)
47 if err != nil {
48 t.Fatal(err)
49 }
50 got, err = aead.Open(nil, current[:aead.NonceSize()], current[aead.NonceSize():], nil)
51 if err != nil || !bytes.Equal(got, plaintext) {
52 t.Fatal("old reader cannot read new envelope", err)
53 }
54 }
55}
56func TestNamespacePurposeKeyAndTamperIsolation(t *testing.T) {
57 s, _ := New(testKey(), "oficina/home")
58 ct, err := s.Seal("pending", []byte("private"))
59 if err != nil {
60 t.Fatal(err)
61 }
62 for _, ns := range []string{"oficina/docs/handoff", "oficina/sheets"} {
63 other, _ := New(testKey(), ns)
64 if _, err := other.Open("pending", ct); err == nil {
65 t.Fatal("namespace crossed")
66 }
67 }
68 if _, err := s.Open("inbox", ct); err == nil {
69 t.Fatal("purpose crossed")
70 }
71 other, _ := New(bytes.Repeat([]byte{99}, 32), "oficina/home")
72 if _, err := other.Open("pending", ct); err == nil {
73 t.Fatal("key crossed")
74 }
75 for i := range ct {
76 bad := append([]byte(nil), ct...)
77 bad[i] ^= 1
78 if _, err := s.Open("pending", bad); err == nil {
79 t.Fatal("altered envelope accepted")
80 }
81 }
82 for i := 0; i < len(ct); i++ {
83 if _, err := s.Open("pending", ct[:i]); err == nil {
84 t.Fatal("truncated envelope accepted")
85 }
86 }
87}
88func TestConstructorCopiesKeyAndRejectsAmbiguousNamespaces(t *testing.T) {
89 key := testKey()
90 s, err := New(key, "oficina/home")
91 if err != nil {
92 t.Fatal(err)
93 }
94 clear(key)
95 expected, _ := New(testKey(), "oficina/home")
96 var wg sync.WaitGroup
97 for i := 0; i < 8; i++ {
98 wg.Add(1)
99 go func() {
100 defer wg.Done()
101 ct, err := s.Seal("parallel", []byte("value"))
102 if err != nil {
103 t.Error(err)
104 return
105 }
106 p, err := expected.Open("parallel", ct)
107 if err != nil || string(p) != "value" {
108 t.Error("caller key mutation changed sealer")
109 }
110 }()
111 }
112 wg.Wait()
113 for _, ns := range []string{"", "a:b", "a\n", "a b", string(bytes.Repeat([]byte{'a'}, 129))} {
114 if _, err := New(testKey(), ns); err == nil {
115 t.Fatal("invalid namespace accepted")
116 }
117 }
118 for _, n := range []int{0, 31, 33} {
119 if _, err := New(make([]byte, n), "oficina/home"); err == nil {
120 t.Fatal("invalid key length accepted")
121 }
122 }
123}
124