summaryrefslogtreecommitdiff
path: root/compat-test/compat_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'compat-test/compat_test.go')
-rw-r--r--compat-test/compat_test.go167
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)
+ }
+ })
+}