package ownwire_sdk_test import ( "crypto/hmac" "crypto/sha256" "encoding/hex" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" sdk "ownwire.net/ownwire-sdk" ) func derive_nonce_reference(shared_key [32]byte, session_uuid_bytes [16]byte, salt16 [16]byte, seq_num uint64, is_response bool) [12]byte { seq_be8 := [8]byte{} for i := 7; i >= 0; i-- { seq_be8[i] = byte(seq_num & 0xff) seq_num >>= 8 } flag := byte(0) if is_response { flag = 1 } mac := hmac.New(sha256.New, shared_key[:]) mac.Write([]byte("ownwire/v1:gcm-nonce")) mac.Write(session_uuid_bytes[:]) mac.Write(salt16[:]) mac.Write(seq_be8[:]) mac.Write([]byte{flag}) sum := mac.Sum(nil) var iv [12]byte copy(iv[:], sum[:12]) return iv } var _ = Describe("Crypto", func() { It("parses UUID bytes", func() { uuid_str := "cb653f53-6f7d-4aeb-ba0d-d2b17c290d8a" uuid_bytes, err := sdk.ParseUUIDBytes(uuid_str) Expect(err).To(BeNil()) Expect(hex.EncodeToString(uuid_bytes[:])).To(Equal("cb653f536f7d4aebba0dd2b17c290d8a")) }) It("derives nonce exactly as reference implementation", func() { var shared_key [32]byte for i := 0; i < 32; i++ { shared_key[i] = byte(i) } uuid_bytes, err := sdk.ParseUUIDBytes("cb653f53-6f7d-4aeb-ba0d-d2b17c290d8a") Expect(err).To(BeNil()) var salt16 [16]byte for i := 0; i < 16; i++ { salt16[i] = byte(0xa0 + i) } seq_num := uint64(0x0102030405060708) got := sdk.DeriveNonce(shared_key, uuid_bytes, salt16, seq_num, false) want := derive_nonce_reference(shared_key, uuid_bytes, salt16, seq_num, false) Expect(got).To(Equal(want)) }) It("encrypts and decrypts roundtrip", func() { var shared_key [32]byte for i := 0; i < 32; i++ { shared_key[i] = byte(0x55 ^ i) } uuid_bytes, err := sdk.ParseUUIDBytes("cb653f53-6f7d-4aeb-ba0d-d2b17c290d8a") Expect(err).To(BeNil()) plain_text := []byte("hello ownwire") seq_num := uint64(123) enc, err := sdk.EncryptAESGCM(shared_key, uuid_bytes, plain_text, seq_num, false) Expect(err).To(BeNil()) Expect(enc.ContentB64).ToNot(BeEmpty()) Expect(enc.SaltHex).To(HaveLen(32)) // 16 bytes hex out, err := sdk.DecryptAESGCM(shared_key, uuid_bytes, enc.ContentB64, enc.SaltHex, seq_num, false) Expect(err).To(BeNil()) Expect(string(out)).To(Equal(string(plain_text))) }) It("fails decrypt if seq changes", func() { var shared_key [32]byte for i := 0; i < 32; i++ { shared_key[i] = byte(0x11 + i) } uuid_bytes, err := sdk.ParseUUIDBytes("cb653f53-6f7d-4aeb-ba0d-d2b17c290d8a") Expect(err).To(BeNil()) enc, err := sdk.EncryptAESGCM(shared_key, uuid_bytes, []byte("hello"), 1, false) Expect(err).To(BeNil()) _, err = sdk.DecryptAESGCM(shared_key, uuid_bytes, enc.ContentB64, enc.SaltHex, 2, false) Expect(err).ToNot(BeNil()) }) })