//go:build phoboscref /* SPDX-License-Identifier: MIT * * Phobos */ package phobos import ( "bytes" "math/rand" "testing" "golang.zx2c4.com/wireguard/windows/phobos/cobf" "golang.zx2c4.com/wireguard/windows/phobos/cref" ) var referenceKeys = [][]byte{ []byte("k"), []byte("phobos"), []byte("Ic0OGtSf1BdMmMDzs7GmYRuPS/HGmNXsSU9EOWEeuQI="), bytes.Repeat([]byte{0xFE}, 200), } func TestXORMatchesReference(t *testing.T) { rng := rand.New(rand.NewSource(1)) for _, key := range referenceKeys { for _, length := range []int{1, 4, 16, 63, 64, 148, 1499, 1500, 1501, 4096, 9000} { data := make([]byte, length) rng.Read(data) want := cref.XOR(data, key) got := bytes.Clone(data) NewObfuscator(key).xorData(got) if !bytes.Equal(got, want) { t.Fatalf("xor mismatch: keylen=%d length=%d", len(key), length) } } } } func TestXORCacheMatchesReference(t *testing.T) { rng := rand.New(rand.NewSource(2)) key := referenceKeys[2] obfuscator := NewObfuscator(key) for range 300 { length := 1 + rng.Intn(1600) data := make([]byte, length) rng.Read(data) want := cref.XOR(data, key) got := bytes.Clone(data) obfuscator.xorData(got) if !bytes.Equal(got, want) { t.Fatalf("cached xor mismatch at length %d", length) } } } func TestStreamCipherMatchesReference(t *testing.T) { rng := rand.New(rand.NewSource(3)) for _, key := range referenceKeys { for _, length := range []int{1, 64, 65, 1000, 20000} { data := make([]byte, length) rng.Read(data) split := length / 3 want := cref.Stream(data, key, split) got := bytes.Clone(data) cipher := cobf.NewStreamCipher(key) cipher.Apply(got[:split]) cipher.Apply(got[split:]) if !bytes.Equal(got, want) { t.Fatalf("stream cipher mismatch: keylen=%d length=%d", len(key), length) } } } } var wireLengths = []int{32, 64, 92, 148, 176, 1024, 1420, 2000, 9000} func goEncode(key, payload []byte, maxDummy, obfuscateBytes int) []byte { buf := make([]byte, BufferSize) copy(buf, payload) n := NewObfuscator(key).Encode(buf, len(payload), maxDummy, obfuscateBytes) if n < 0 { return nil } return buf[:n] } func goDecode(key, encoded []byte, obfuscateBytes int) []byte { buf := bytes.Clone(encoded) n := NewObfuscator(key).Decode(buf, len(buf), obfuscateBytes) if n < 0 { return nil } return buf[:n] } func wirePacket(rng *rand.Rand, length int) []byte { payload := make([]byte, length) rng.Read(payload) payload[0] = byte(1 + rng.Intn(4)) payload[1], payload[2], payload[3] = 0, 0, 0 return payload } func TestDecodeAgreesWithReference(t *testing.T) { rng := rand.New(rand.NewSource(4)) for _, key := range referenceKeys { for _, obfuscateBytes := range []int{0, 4, 16, 64} { for _, length := range append([]int{4, 8, 16}, wireLengths...) { encoded := cref.Encode(wirePacket(rng, length), key, DefaultMaxDummy, obfuscateBytes, BufferSize) if !bytes.Equal(goDecode(key, encoded, obfuscateBytes), cref.Decode(encoded, key, obfuscateBytes)) { t.Fatalf("decode disagrees with reference: keylen=%d length=%d obf=%d", len(key), length, obfuscateBytes) } } } } } func TestEncodeDecodeInteropWithReference(t *testing.T) { rng := rand.New(rand.NewSource(5)) for _, key := range referenceKeys { for _, obfuscateBytes := range []int{0, 16, 64, 148, 200, 512} { for _, length := range wireLengths { for range 16 { payload := wirePacket(rng, length) encoded := cref.Encode(payload, key, DefaultMaxDummy, obfuscateBytes, BufferSize) if !bytes.Equal(cref.Decode(encoded, key, obfuscateBytes), payload) { t.Fatalf("C cannot decode its own output: keylen=%d length=%d obf=%d", len(key), length, obfuscateBytes) } if !bytes.Equal(goDecode(key, encoded, obfuscateBytes), payload) { t.Fatalf("go cannot decode C output: keylen=%d length=%d obf=%d", len(key), length, obfuscateBytes) } encoded = goEncode(key, payload, DefaultMaxDummy, obfuscateBytes) if !bytes.Equal(cref.Decode(encoded, key, obfuscateBytes), payload) { t.Fatalf("C cannot decode Go output: keylen=%d length=%d obf=%d", len(key), length, obfuscateBytes) } } } } } }