diff options
Diffstat (limited to 'compat-test/compat_test.go')
-rw-r--r-- | compat-test/compat_test.go | 167 |
1 files changed, 167 insertions, 0 deletions
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) + } + }) +} |