diff options
Diffstat (limited to 'compat-test')
-rw-r--r-- | compat-test/README.md | 44 | ||||
-rw-r--r-- | compat-test/compat_test.go | 167 | ||||
-rw-r--r-- | compat-test/go.mod | 17 | ||||
-rw-r--r-- | compat-test/go.sum | 10 |
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= |