package seal import ( "crypto/ecdh" "encoding/base64" "encoding/json" "os" "testing" ) type fixture struct { Recipient KeyPair `json:"recipient"` Sealed []struct { Plaintext string `json:"plaintext"` Box Box `json:"box"` } `json:"sealed"` Vectors []struct { Plaintext string `json:"plaintext"` EphPrivate string `json:"ephPrivate"` IV string `json:"iv"` Box Box `json:"box"` } `json:"vectors"` } func readFixture(t *testing.T) fixture { t.Helper() raw, err := os.ReadFile("testdata/sealed-by-licence-manager.json") if err != nil { t.Fatal(err) } var f fixture if err := json.Unmarshal(raw, &f); err != nil { t.Fatal(err) } if len(f.Sealed) == 0 || len(f.Vectors) == 0 { t.Fatal("the fixture holds no boxes") } return f } // Every box the licence manager's own Seal made opens here to its plaintext. func TestABoxTheLicenceManagerSealedOpens(t *testing.T) { f := readFixture(t) for _, s := range f.Sealed { got, err := Open(s.Box, f.Recipient.PrivateKey) if err != nil || got != s.Plaintext { t.Fatalf("opened %q, %v; want %q", got, err, s.Plaintext) } } } // Given the same one-time key and iv, this package seals byte for byte what the licence manager sealed: // the reverse direction, so whatever opens the licence manager's boxes opens these. func TestSealIsByteForByteTheLicenceManagersBox(t *testing.T) { f := readFixture(t) for _, v := range f.Vectors { d := base64.StdEncoding.DecodeString ephRaw, err1 := d(v.EphPrivate) iv, err2 := d(v.IV) if err1 != nil || err2 != nil { t.Fatal(err1, err2) } eph, err := ecdh.X25519().NewPrivateKey(ephRaw) if err != nil { t.Fatal(err) } got, err := sealWith(v.Plaintext, f.Recipient.PublicKey, eph, iv) if err != nil { t.Fatal(err) } if got != v.Box { t.Fatalf("sealed %+v\nthe licence manager sealed %+v", got, v.Box) } if plain, err := Open(got, f.Recipient.PrivateKey); err != nil || plain != v.Plaintext { t.Fatalf("reopened %q, %v", plain, err) } } } // A box the agent module's TypeScript sealed (the fixture the licence manager keeps) opens here too. func TestABoxSealedInTypeScriptOpens(t *testing.T) { raw, err := os.ReadFile("testdata/sealed-by-typescript.json") if err != nil { t.Fatal(err) } var f struct { PrivateKey string `json:"privateKey"` Box Box `json:"box"` Plaintext string `json:"plaintext"` } if err := json.Unmarshal(raw, &f); err != nil { t.Fatal(err) } if got, err := Open(f.Box, f.PrivateKey); err != nil || got != f.Plaintext { t.Fatalf("opened %q, %v", got, err) } } // What Seal makes opens with its recipient's key and no other, and a fresh box differs every time. func TestABoxOpensOnlyForItsRecipient(t *testing.T) { a, err := GenerateKeyPair() if err != nil { t.Fatal(err) } b, _ := GenerateKeyPair() box, err := Seal("a token", a.PublicKey) if err != nil { t.Fatal(err) } if got, err := Open(box, a.PrivateKey); err != nil || got != "a token" { t.Fatalf("opened %q, %v", got, err) } if _, err := Open(box, b.PrivateKey); err == nil { t.Fatal("a box opened for another key") } again, _ := Seal("a token", a.PublicKey) if again.Eph == box.Eph || again.IV == box.IV { t.Fatal("two boxes share a one-time key or iv") } } // A box changed in any field, or of another version, does not open. func TestATamperedBoxDoesNotOpen(t *testing.T) { f := readFixture(t) good := f.Sealed[1].Box flip := func(s string) string { b, _ := base64.StdEncoding.DecodeString(s) b[len(b)-1] ^= 1 return base64.StdEncoding.EncodeToString(b) } for name, box := range map[string]Box{ "ct": {V: 1, Eph: good.Eph, IV: good.IV, Tag: good.Tag, Ct: flip(good.Ct)}, "tag": {V: 1, Eph: good.Eph, IV: good.IV, Tag: flip(good.Tag), Ct: good.Ct}, "iv": {V: 1, Eph: good.Eph, IV: flip(good.IV), Tag: good.Tag, Ct: good.Ct}, "eph": {V: 1, Eph: flip(good.Eph), IV: good.IV, Tag: good.Tag, Ct: good.Ct}, "version": {V: 2, Eph: good.Eph, IV: good.IV, Tag: good.Tag, Ct: good.Ct}, } { if _, err := Open(box, f.Recipient.PrivateKey); err == nil { t.Fatalf("a box with a changed %s opened", name) } } } // A key that is not X25519 PEM is refused, not misread. func TestAKeyOfAnotherKindIsRefused(t *testing.T) { if _, err := Seal("x", "not a key"); err == nil { t.Fatal("sealed to text") } f := readFixture(t) if _, err := Open(f.Sealed[0].Box, f.Recipient.PublicKey); err == nil { t.Fatal("opened with a public key") } if _, err := Seal("x", f.Recipient.PrivateKey); err == nil { t.Fatal("sealed to a private key") } }