summaryrefslogtreecommitdiff
path: root/compat-test
diff options
context:
space:
mode:
Diffstat (limited to 'compat-test')
-rw-r--r--compat-test/README.md44
-rw-r--r--compat-test/compat_test.go167
-rw-r--r--compat-test/go.mod17
-rw-r--r--compat-test/go.sum10
4 files changed, 238 insertions, 0 deletions
diff --git a/compat-test/README.md b/compat-test/README.md
new file mode 100644
index 0000000..c1e91b8
--- /dev/null
+++ b/compat-test/README.md
@@ -0,0 +1,44 @@
+# Kate libsodium Compatibility Tests
+
+This directory contains tests to verify that the `kate` package's `seal` and `open` functions are compatible with the real libsodium implementation.
+
+## Why?
+
+The `kate` library is designed to be CGO-free to avoid the complexity and deployment challenges that come with C dependencies. Rather than requiring applications to link against libsodium, `kate` implements a pure Go version of the NaCl secretbox encryption scheme.
+
+This separate compatibility test project verifies that `kate`'s implementation produces ciphertext that is fully interoperable with libsodium while keeping the CGO dependency isolated from the main package. This way, applications get the benefits of a pure Go library while maintaining confidence in libsodium compatibility.
+
+## Setup
+
+The tests require libsodium to be installed on your system. The project uses the `github.com/jamesruan/sodium` Go bindings for libsodium.
+
+### Installing libsodium
+
+On macOS:
+```bash
+brew install libsodium
+```
+
+On Ubuntu/Debian:
+```bash
+sudo apt-get install libsodium-dev
+```
+
+On CentOS/RHEL:
+```bash
+sudo yum install libsodium-devel
+```
+
+## Running the Tests
+
+```bash
+cd compat-test
+go test
+```
+
+## Test Cases
+
+The test suite includes:
+
+1. **KateEncrypt_LibsodiumDecrypt**: Encrypts data with kate's library and decrypts with libsodium
+2. **LibsodiumEncrypt_KateDecrypt**: Encrypts data with libsodium and decrypts with kate's library
diff --git a/compat-test/compat_test.go b/compat-test/compat_test.go
new file mode 100644
index 0000000..2b0bfd7
--- /dev/null
+++ b/compat-test/compat_test.go
@@ -0,0 +1,167 @@
+package main
+
+import (
+ "crypto/rand"
+ "encoding/hex"
+ "io"
+ "net/http"
+ "net/http/httptest"
+ "testing"
+ "testing/quick"
+
+ "git.tjp.lol/authentic_kate"
+ "github.com/jamesruan/sodium"
+)
+
+type ByteSerDes struct{}
+
+func (ByteSerDes) Serialize(w io.Writer, data []byte) error {
+ _, err := w.Write(data)
+ return err
+}
+
+func (ByteSerDes) Deserialize(r io.Reader, data *[]byte) error {
+ buf, err := io.ReadAll(r)
+ if err != nil {
+ return err
+ }
+ *data = buf
+ return nil
+}
+
+func kateSeal(key [32]byte, plaintext []byte) []byte {
+ keyHex := hex.EncodeToString(key[:])
+
+ auth := kate.New(keyHex, kate.AuthConfig[[]byte]{
+ SerDes: ByteSerDes{},
+ CookieName: "test",
+ })
+
+ w := httptest.NewRecorder()
+ if err := auth.Set(w, plaintext); err != nil {
+ panic(err)
+ }
+
+ cookies := w.Result().Cookies()
+ if len(cookies) == 0 {
+ panic("No cookie set")
+ }
+
+ encryptedBytes, err := hex.DecodeString(cookies[0].Value)
+ if err != nil {
+ panic(err)
+ }
+
+ return encryptedBytes
+}
+
+func libsodiumSeal(key [32]byte, plaintext []byte) []byte {
+ var nonce [24]byte
+ if _, err := rand.Read(nonce[:]); err != nil {
+ panic(err)
+ }
+
+ ciphertextAndMac := sodium.Bytes(plaintext).SecretBox(
+ sodium.SecretBoxNonce{Bytes: nonce[:]},
+ sodium.SecretBoxKey{Bytes: key[:]},
+ )
+
+ result := make([]byte, 24+len(ciphertextAndMac))
+ copy(result[:24], nonce[:])
+ copy(result[24:], ciphertextAndMac)
+
+ return result
+}
+
+func kateOpen(key [32]byte, box []byte) ([]byte, bool) {
+ keyHex := hex.EncodeToString(key[:])
+
+ auth := kate.New(keyHex, kate.AuthConfig[[]byte]{
+ SerDes: ByteSerDes{},
+ CookieName: "test",
+ })
+
+ cookieValue := hex.EncodeToString(box)
+ req := httptest.NewRequest("GET", "/", nil)
+ req.AddCookie(&http.Cookie{Name: "test", Value: cookieValue})
+
+ var decryptedData []byte
+ var success bool
+ handler := auth.Optional(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ data, ok := auth.Get(r.Context())
+ if ok {
+ decryptedData = data
+ success = true
+ }
+ }))
+
+ testW := httptest.NewRecorder()
+ handler.ServeHTTP(testW, req)
+
+ return decryptedData, success
+}
+
+func libsodiumOpen(key [32]byte, box []byte) ([]byte, bool) {
+ if len(box) < 24 {
+ return nil, false
+ }
+
+ nonce := box[:24]
+ ciphertextAndMac := box[24:]
+
+ decrypted, err := sodium.Bytes(ciphertextAndMac).SecretBoxOpen(
+ sodium.SecretBoxNonce{Bytes: nonce},
+ sodium.SecretBoxKey{Bytes: key[:]},
+ )
+ if err != nil {
+ return nil, false
+ }
+
+ return decrypted, true
+}
+
+func TestCrossLibraryCompatibility(t *testing.T) {
+ t.Run("KateEncrypt_LibsodiumDecrypt", func(t *testing.T) {
+ f := func(data []byte) bool {
+ if len(data) == 0 {
+ return true
+ }
+
+ var key [32]byte
+ if _, err := rand.Read(key[:]); err != nil {
+ return false
+ }
+
+ kateBox := kateSeal(key, data)
+ decrypted, ok := libsodiumOpen(key, kateBox)
+
+ return ok && string(decrypted) == string(data)
+ }
+
+ if err := quick.Check(f, nil); err != nil {
+ t.Errorf("Property test failed: %v", err)
+ }
+ })
+
+ t.Run("LibsodiumEncrypt_KateDecrypt", func(t *testing.T) {
+ f := func(data []byte) bool {
+ if len(data) == 0 {
+ return true
+ }
+
+ var key [32]byte
+ if _, err := rand.Read(key[:]); err != nil {
+ return false
+ }
+
+ libsodiumBox := libsodiumSeal(key, data)
+ decrypted, ok := kateOpen(key, libsodiumBox)
+
+ return ok && string(decrypted) == string(data)
+ }
+
+ if err := quick.Check(f, nil); err != nil {
+ t.Errorf("Property test failed: %v", err)
+ }
+ })
+}
diff --git a/compat-test/go.mod b/compat-test/go.mod
new file mode 100644
index 0000000..c7711c9
--- /dev/null
+++ b/compat-test/go.mod
@@ -0,0 +1,17 @@
+module git.tjp.lol/authentic_kate/compat-test
+
+go 1.24.4
+
+require (
+ git.tjp.lol/authentic_kate v0.0.0-00010101000000-000000000000
+ github.com/jamesruan/sodium v1.0.14
+)
+
+require (
+ cloud.google.com/go/compute/metadata v0.3.0 // indirect
+ golang.org/x/crypto v0.39.0 // indirect
+ golang.org/x/oauth2 v0.30.0 // indirect
+ golang.org/x/sys v0.33.0 // indirect
+)
+
+replace git.tjp.lol/authentic_kate => ../
diff --git a/compat-test/go.sum b/compat-test/go.sum
new file mode 100644
index 0000000..c96829d
--- /dev/null
+++ b/compat-test/go.sum
@@ -0,0 +1,10 @@
+cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
+cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
+github.com/jamesruan/sodium v1.0.14 h1:JfOHobip/lUWouxHV3PwYwu3gsLewPrDrZXO3HuBzUU=
+github.com/jamesruan/sodium v1.0.14/go.mod h1:GK2+LACf7kuVQ9k7Irk0MB2B65j5rVqkz+9ylGIggZk=
+golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
+golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
+golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
+golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
+golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
+golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=