Browse Source

Add new obfuscation package

tags/v2.1.11^2^2
9seconds 2 months ago
parent
commit
d0065d35c2

+ 34
- 0
mtglib/internal/obfuscation/conn.go View File

@@ -0,0 +1,34 @@
1
+package obfuscation
2
+
3
+import (
4
+	"crypto/cipher"
5
+
6
+	"github.com/9seconds/mtg/v2/essentials"
7
+)
8
+
9
+type conn struct {
10
+	essentials.Conn
11
+
12
+	sendCipher cipher.Stream
13
+	recvCipher cipher.Stream
14
+}
15
+
16
+func (c conn) Read(p []byte) (int, error) {
17
+	n, err := c.Conn.Read(p)
18
+	if err != nil {
19
+		return n, err
20
+	}
21
+
22
+	c.recvCipher.XORKeyStream(p, p[:n])
23
+
24
+	return n, nil
25
+}
26
+
27
+func (c conn) Write(p []byte) (int, error) {
28
+	// yes, this is a bit violent and goes against a contract in io.Writer
29
+	// but we do it to avoid creating a new buffer just to perform this
30
+	// encryption.
31
+	c.sendCipher.XORKeyStream(p, p)
32
+
33
+	return c.Conn.Write(p)
34
+}

+ 102
- 0
mtglib/internal/obfuscation/conn_test.go View File

@@ -0,0 +1,102 @@
1
+package obfuscation
2
+
3
+import (
4
+	"crypto/aes"
5
+	"crypto/cipher"
6
+	"encoding/hex"
7
+	"testing"
8
+
9
+	"github.com/9seconds/mtg/v2/essentials"
10
+	"github.com/9seconds/mtg/v2/internal/testlib"
11
+	"github.com/stretchr/testify/assert"
12
+	"github.com/stretchr/testify/mock"
13
+	"github.com/stretchr/testify/suite"
14
+)
15
+
16
+type ConnTestSuite struct {
17
+	suite.Suite
18
+
19
+	secret []byte
20
+}
21
+
22
+func (s *ConnTestSuite) SetupSuite() {
23
+	secret := [32]byte{}
24
+	s.secret = secret[:]
25
+}
26
+
27
+func (s *ConnTestSuite) TestRead() {
28
+	testData := map[string]string{
29
+		"data1": "b8f4b41993",
30
+		"":      "",
31
+		"___":   "83ca9f",
32
+	}
33
+
34
+	for incoming, outgoing := range testData {
35
+		s.T().Run(incoming, func(t *testing.T) {
36
+			connMock := &testlib.EssentialsConnMock{}
37
+			testConn := s.makeConn(connMock)
38
+			data := make([]byte, len(incoming))
39
+
40
+			connMock.On("Read", make([]byte, len(incoming))).Return(len(incoming), nil).Run(func(args mock.Arguments) {
41
+				arg := args.Get(0).([]byte)
42
+				copy(arg, []byte(incoming))
43
+			})
44
+
45
+			n, err := testConn.Read(data)
46
+
47
+			assert.Equal(t, len(data), n)
48
+			assert.NoError(t, err)
49
+			assert.Equal(t, outgoing, hex.EncodeToString(data))
50
+
51
+			connMock.AssertExpectations(t)
52
+		})
53
+	}
54
+}
55
+
56
+func (s *ConnTestSuite) TestWrite() {
57
+	testData := map[string]string{
58
+		"b8f4b41993": "data1",
59
+		"":           "",
60
+		"83ca9f":     "___",
61
+	}
62
+
63
+	for incoming, outgoing := range testData {
64
+		s.T().Run(incoming, func(t *testing.T) {
65
+			connMock := &testlib.EssentialsConnMock{}
66
+			testConn := s.makeConn(connMock)
67
+			toWrite, _ := hex.DecodeString(incoming)
68
+			data := make([]byte, len(toWrite))
69
+
70
+			connMock.On("Write", []byte(outgoing)).Return(len(toWrite), nil)
71
+
72
+			n, err := testConn.Write(toWrite)
73
+			assert.Equal(t, len(data), n)
74
+			assert.NoError(t, err)
75
+
76
+			connMock.AssertExpectations(t)
77
+		})
78
+	}
79
+}
80
+
81
+func (s *ConnTestSuite) makeConn(rawConn *testlib.EssentialsConnMock) essentials.Conn {
82
+	rblock, err := aes.NewCipher(s.secret)
83
+	if err != nil {
84
+		panic(err)
85
+	}
86
+
87
+	wblock, err := aes.NewCipher(s.secret)
88
+	if err != nil {
89
+		panic(err)
90
+	}
91
+
92
+	return conn{
93
+		Conn:       rawConn,
94
+		sendCipher: cipher.NewCTR(wblock, s.secret[:aes.BlockSize]),
95
+		recvCipher: cipher.NewCTR(rblock, s.secret[:aes.BlockSize]),
96
+	}
97
+}
98
+
99
+func TestConn(t *testing.T) {
100
+	t.Parallel()
101
+	suite.Run(t, &ConnTestSuite{})
102
+}

+ 111
- 0
mtglib/internal/obfuscation/handshake_frame.go View File

@@ -0,0 +1,111 @@
1
+package obfuscation
2
+
3
+import (
4
+	"crypto/rand"
5
+	"encoding/binary"
6
+	"slices"
7
+)
8
+
9
+// https://core.telegram.org/mtproto/mtproto-transports#transport-obfuscation
10
+const (
11
+	// default DC is nothing is selected
12
+	defaultDC = 2
13
+
14
+	// the length of the handshake frame. Always 64 bytes
15
+	hfLen = 64
16
+
17
+	hfLenKey            = 32
18
+	hfLenIV             = 16
19
+	hfLenConnectionType = 4
20
+
21
+	// A structure of obfuscated handshake frame is following:
22
+	//
23
+	//	[frameOffsetFirst:frameOffsetKey:frameOffsetIV:frameOffsetMagic:frameOffsetDC:frameOffsetEnd].
24
+	//
25
+	//	- 8 bytes of noise
26
+	//	- 32 bytes of AES Key
27
+	//	- 16 bytes of AES IV
28
+	//	- 4 bytes of 'connection type' - this has some setting like a connection type
29
+	//	- 2 bytes of 'DC'. DC is little endian int16
30
+	//	- 2 bytes of noise
31
+	hfOffsetKey            = 8
32
+	hfOffsetIV             = hfOffsetKey + hfLenKey
33
+	hfOffsetConnectionType = hfOffsetIV + hfLenIV
34
+	hfOffsetDC             = hfOffsetConnectionType + hfLenConnectionType
35
+)
36
+
37
+// Connection-Type: Secure. We support only fake tls.
38
+var hfConnectionType = [hfLenConnectionType]byte{0xdd, 0xdd, 0xdd, 0xdd}
39
+
40
+type handshakeFrame struct {
41
+	data [hfLen]byte
42
+}
43
+
44
+func (h *handshakeFrame) key() []byte {
45
+	return h.data[hfOffsetKey : hfOffsetKey+hfLenKey]
46
+}
47
+
48
+func (h *handshakeFrame) iv() []byte {
49
+	return h.data[hfOffsetIV : hfOffsetIV+hfLenIV]
50
+}
51
+
52
+func (h *handshakeFrame) connectionType() []byte {
53
+	return h.data[hfOffsetConnectionType : hfOffsetConnectionType+hfLenConnectionType]
54
+}
55
+
56
+func (h *handshakeFrame) dcSlice() []byte {
57
+	return h.data[hfOffsetDC : hfOffsetDC+2]
58
+}
59
+
60
+func (h *handshakeFrame) dc() int {
61
+	idx := int16(binary.LittleEndian.Uint16(h.dcSlice()))
62
+
63
+	switch {
64
+	case idx > 0:
65
+		return int(idx)
66
+	case idx < 0:
67
+		return -int(idx)
68
+	}
69
+
70
+	return defaultDC
71
+}
72
+
73
+func (h *handshakeFrame) revert() {
74
+	slices.Reverse(h.data[hfOffsetKey:hfOffsetConnectionType])
75
+}
76
+
77
+func generateHandshake(dc int) handshakeFrame {
78
+	frame := handshakeFrame{}
79
+
80
+	for {
81
+		if _, err := rand.Read(frame.data[:]); err != nil {
82
+			panic(err)
83
+		}
84
+
85
+		// https://github.com/tdlib/td/blob/master/td/mtproto/TcpTransport.cpp#L157-L158.
86
+		if frame.data[0] == 0xef { // abridged header
87
+			// https://core.telegram.org/mtproto/mtproto-transports#abridged
88
+			continue
89
+		}
90
+
91
+		switch binary.LittleEndian.Uint32(frame.data[:4]) {
92
+		case 0x44414548, // HEAD
93
+			0x54534f50, // POST
94
+			0x20544547, // GET
95
+			0x4954504f, // OPTI
96
+			0x02010316, // ????
97
+			0xdddddddd, // PaddedIntermediate header
98
+			0xeeeeeeee: // Intermediate header
99
+			continue
100
+		}
101
+
102
+		if frame.data[4]|frame.data[5]|frame.data[6]|frame.data[7] == 0 {
103
+			continue
104
+		}
105
+
106
+		copy(frame.connectionType(), hfConnectionType[:])
107
+		binary.LittleEndian.PutUint16(frame.dcSlice(), uint16(dc))
108
+
109
+		return frame
110
+	}
111
+}

+ 33
- 0
mtglib/internal/obfuscation/handshake_frame_fuzz_test.go View File

@@ -0,0 +1,33 @@
1
+package obfuscation
2
+
3
+import (
4
+	"encoding/binary"
5
+	"testing"
6
+
7
+	"github.com/stretchr/testify/assert"
8
+)
9
+
10
+func FuzzGenerateHandshakeFrame(f *testing.F) {
11
+	f.Fuzz(func(t *testing.T, arg int16) {
12
+		frame := generateHandshake(int(arg))
13
+
14
+		assert.NotEqualValues(t, 0xef, frame.data[0])
15
+
16
+		firstBytes := binary.LittleEndian.Uint32(frame.data[:4])
17
+		assert.NotEqualValues(t, 0x44414548, firstBytes)
18
+		assert.NotEqualValues(t, 0x54534f50, firstBytes)
19
+		assert.NotEqualValues(t, 0x20544547, firstBytes)
20
+		assert.NotEqualValues(t, 0x4954504f, firstBytes)
21
+		assert.NotEqualValues(t, 0x02010316, firstBytes)
22
+		assert.NotEqualValues(t, 0xeeeeeeee, firstBytes)
23
+		assert.NotEqualValues(t, 0xdddddddd, firstBytes)
24
+
25
+		assert.NotEqualValues(
26
+			t,
27
+			0,
28
+			frame.data[4]|frame.data[5]|frame.data[6]|frame.data[7])
29
+
30
+		assert.Equal(t, hfConnectionType[:], frame.connectionType())
31
+		assert.EqualValues(t, arg, frame.dc())
32
+	})
33
+}

+ 66
- 0
mtglib/internal/obfuscation/handshake_frame_test.go View File

@@ -0,0 +1,66 @@
1
+package obfuscation
2
+
3
+import (
4
+	"testing"
5
+
6
+	"github.com/stretchr/testify/suite"
7
+)
8
+
9
+type HandshakeFrameTestSuite struct {
10
+	suite.Suite
11
+
12
+	frame    handshakeFrame
13
+	reverted handshakeFrame
14
+}
15
+
16
+func (h *HandshakeFrameTestSuite) SetupSuite() {
17
+	for i := range hfLen {
18
+		h.frame.data[i] = byte(i + 1)
19
+		h.reverted.data[i] = byte(hfLen - i)
20
+	}
21
+}
22
+
23
+func (h *HandshakeFrameTestSuite) TestKey() {
24
+	key := h.frame.key()
25
+	h.EqualValues(8+1, key[0])
26
+	h.EqualValues(8+hfLenKey, key[len(key)-1])
27
+	h.Len(key, hfLenKey)
28
+}
29
+
30
+func (h *HandshakeFrameTestSuite) TestIV() {
31
+	iv := h.frame.iv()
32
+	h.EqualValues(40+1, iv[0])
33
+	h.EqualValues(40+hfLenIV, iv[len(iv)-1])
34
+	h.Len(iv, hfLenIV)
35
+}
36
+
37
+func (h *HandshakeFrameTestSuite) TestConnectionType() {
38
+	connectionType := h.frame.connectionType()
39
+	h.EqualValues(56+1, connectionType[0])
40
+	h.EqualValues(56+hfLenConnectionType, connectionType[len(connectionType)-1])
41
+	h.Len(connectionType, hfLenConnectionType)
42
+}
43
+
44
+func (h *HandshakeFrameTestSuite) TestDCSlice() {
45
+	dcSlice := h.frame.dcSlice()
46
+	h.EqualValues(61, dcSlice[0])
47
+	h.EqualValues(61+1, dcSlice[1])
48
+	h.Len(dcSlice, 2)
49
+}
50
+
51
+func (h *HandshakeFrameTestSuite) TestDC() {
52
+	h.Equal(15933, h.frame.dc())
53
+}
54
+
55
+func (h *HandshakeFrameTestSuite) TestRevert() {
56
+	fr := h.frame
57
+	fr.revert()
58
+
59
+	h.Equal(h.reverted.key(), fr.key())
60
+	h.Equal(h.reverted.iv(), fr.iv())
61
+}
62
+
63
+func TestHandshakeFrame(t *testing.T) {
64
+	t.Parallel()
65
+	suite.Run(t, &HandshakeFrameTestSuite{})
66
+}

+ 79
- 0
mtglib/internal/obfuscation/init_test.go View File

@@ -0,0 +1,79 @@
1
+package obfuscation_test
2
+
3
+import (
4
+	"encoding/base64"
5
+	"encoding/json"
6
+	"fmt"
7
+	"os"
8
+	"path/filepath"
9
+	"strings"
10
+
11
+	"github.com/stretchr/testify/require"
12
+	"github.com/stretchr/testify/suite"
13
+)
14
+
15
+type snapshotBytes struct {
16
+	data []byte
17
+}
18
+
19
+func (s snapshotBytes) MarshalText() ([]byte, error) {
20
+	if len(s.data) == 0 {
21
+		return nil, nil
22
+	}
23
+
24
+	return []byte(base64.RawStdEncoding.EncodeToString(s.data)), nil
25
+}
26
+
27
+func (s *snapshotBytes) UnmarshalText(data []byte) error {
28
+	val, err := base64.RawStdEncoding.DecodeString(string(data))
29
+	if err != nil {
30
+		return fmt.Errorf("cannot unmarshal %v: %w", len(val), err)
31
+	}
32
+
33
+	s.data = val
34
+
35
+	return nil
36
+}
37
+
38
+type ObfuscatedSnapshot struct {
39
+	Secret    snapshotBytes `json:"secret"`
40
+	Frame     snapshotBytes `json:"frame"`
41
+	DC        int16         `json:"dc"`
42
+	Encrypted struct {
43
+		Text   snapshotBytes `json:"text"`
44
+		Cipher snapshotBytes `json:"cipher"`
45
+	} `json:"encrypted"`
46
+	Decrypted struct {
47
+		Text   snapshotBytes `json:"text"`
48
+		Cipher snapshotBytes `json:"cipher"`
49
+	} `json:"decrypted"`
50
+}
51
+
52
+type SnapshotTestSuite struct {
53
+	suite.Suite
54
+
55
+	snapshots map[string]*ObfuscatedSnapshot
56
+}
57
+
58
+func (s *SnapshotTestSuite) Setup(dirname, namePrefix string) {
59
+	s.snapshots = make(map[string]*ObfuscatedSnapshot)
60
+
61
+	files, err := os.ReadDir("testdata")
62
+	require.NoError(s.T(), err)
63
+
64
+	for _, v := range files {
65
+		if !strings.HasPrefix(v.Name(), namePrefix) {
66
+			continue
67
+		}
68
+
69
+		filename := filepath.Join("testdata", v.Name())
70
+
71
+		contents, err := os.ReadFile(filename)
72
+		require.NoError(s.T(), err)
73
+
74
+		value := &ObfuscatedSnapshot{}
75
+		require.NoError(s.T(), json.Unmarshal(contents, value))
76
+
77
+		s.snapshots[v.Name()] = value
78
+	}
79
+}

+ 87
- 0
mtglib/internal/obfuscation/obfuscator.go View File

@@ -0,0 +1,87 @@
1
+package obfuscation
2
+
3
+import (
4
+	"crypto/aes"
5
+	"crypto/cipher"
6
+	"crypto/sha256"
7
+	"crypto/subtle"
8
+	"encoding/hex"
9
+	"fmt"
10
+	"hash"
11
+	"io"
12
+
13
+	"github.com/9seconds/mtg/v2/essentials"
14
+)
15
+
16
+type Obfuscator struct {
17
+	Secret []byte
18
+}
19
+
20
+func (o Obfuscator) ReadHandshake(r essentials.Conn) (int, essentials.Conn, error) {
21
+	frame := handshakeFrame{}
22
+
23
+	if _, err := io.ReadFull(r, frame.data[:]); err != nil {
24
+		return 0, nil, fmt.Errorf("cannot read frame: %w", err)
25
+	}
26
+
27
+	hasher := sha256.New()
28
+	recvCipher := o.getCipher(&frame, hasher)
29
+
30
+	frame.revert()
31
+	hasher.Reset()
32
+	sendCipher := o.getCipher(&frame, hasher)
33
+
34
+	recvCipher.XORKeyStream(frame.data[:], frame.data[:])
35
+
36
+	if val := frame.connectionType(); subtle.ConstantTimeCompare(val, hfConnectionType[:]) != 1 {
37
+		return 0, nil, fmt.Errorf("unsupported connection type: %s", hex.EncodeToString(val))
38
+	}
39
+
40
+	cn := conn{
41
+		Conn:       r,
42
+		recvCipher: recvCipher,
43
+		sendCipher: sendCipher,
44
+	}
45
+
46
+	return frame.dc(), cn, nil
47
+}
48
+
49
+func (o Obfuscator) SendHandshake(w essentials.Conn, dc int) (essentials.Conn, error) {
50
+	frame := generateHandshake(dc)
51
+	copyFrame := frame
52
+	hasher := sha256.New()
53
+
54
+	sendCipher := o.getCipher(&frame, hasher)
55
+
56
+	frame.revert()
57
+	hasher.Reset()
58
+	recvCipher := o.getCipher(&frame, hasher)
59
+
60
+	sendCipher.XORKeyStream(frame.data[:], frame.data[:])
61
+	copy(frame.key(), copyFrame.key())
62
+	copy(frame.iv(), copyFrame.iv())
63
+
64
+	if _, err := w.Write(frame.data[:]); err != nil {
65
+		return nil, fmt.Errorf("cannot send a handshake: %w", err)
66
+	}
67
+
68
+	return conn{
69
+		Conn:       w,
70
+		recvCipher: recvCipher,
71
+		sendCipher: sendCipher,
72
+	}, nil
73
+}
74
+
75
+func (o Obfuscator) getCipher(f *handshakeFrame, hasher hash.Hash) cipher.Stream {
76
+	blockKey := f.key()
77
+
78
+	if o.Secret != nil {
79
+		hasher.Write(blockKey)
80
+		hasher.Write(o.Secret)
81
+		blockKey = hasher.Sum(nil)
82
+	}
83
+
84
+	block, _ := aes.NewCipher(blockKey)
85
+
86
+	return cipher.NewCTR(block, f.iv())
87
+}

+ 63
- 0
mtglib/internal/obfuscation/obfuscator_fuzz_test.go View File

@@ -0,0 +1,63 @@
1
+package obfuscation_test
2
+
3
+import (
4
+	"bytes"
5
+	"testing"
6
+
7
+	"github.com/9seconds/mtg/v2/internal/testlib"
8
+	"github.com/9seconds/mtg/v2/mtglib"
9
+	"github.com/9seconds/mtg/v2/mtglib/internal/obfuscation"
10
+	"github.com/stretchr/testify/assert"
11
+	"github.com/stretchr/testify/mock"
12
+)
13
+
14
+func FuzzClientServerHandshakes(f *testing.F) {
15
+	f.Add(int16(1), make([]byte, mtglib.SecretKeyLength))
16
+
17
+	f.Fuzz(func(t *testing.T, dc int16, data []byte) {
18
+		if dc <= 0 {
19
+			dc = 1
20
+		}
21
+
22
+		client := obfuscation.Obfuscator{
23
+			Secret: data,
24
+		}
25
+		server := client
26
+
27
+		clientToServerBuf := &bytes.Buffer{}
28
+
29
+		writeConnMock := &testlib.EssentialsConnMock{}
30
+		writeConnMock.
31
+			On("Write", mock.AnythingOfType("[]uint8")).
32
+			Once().
33
+			Return(64, nil).
34
+			Run(func(args mock.Arguments) {
35
+				arg := args.Get(0).([]byte)
36
+				n, err := clientToServerBuf.Write(arg)
37
+				assert.Equal(t, 64, n)
38
+				assert.NoError(t, err)
39
+			})
40
+
41
+		readConnMock := &testlib.EssentialsConnMock{}
42
+		readConnMock.
43
+			On("Read", mock.AnythingOfType("[]uint8")).
44
+			Once().
45
+			Return(64, nil).
46
+			Run(func(args mock.Arguments) {
47
+				arg := args.Get(0).([]byte)
48
+				n, err := clientToServerBuf.Read(arg)
49
+				assert.Equal(t, 64, n)
50
+				assert.NoError(t, err)
51
+			})
52
+
53
+		_, err := client.SendHandshake(writeConnMock, int(dc))
54
+		assert.NoError(t, err)
55
+
56
+		readDc, _, err := server.ReadHandshake(readConnMock)
57
+		assert.NoError(t, err)
58
+		assert.EqualValues(t, dc, readDc)
59
+
60
+		writeConnMock.AssertExpectations(t)
61
+		readConnMock.AssertExpectations(t)
62
+	})
63
+}

+ 94
- 0
mtglib/internal/obfuscation/obfuscator_test.go View File

@@ -0,0 +1,94 @@
1
+package obfuscation_test
2
+
3
+import (
4
+	"bytes"
5
+	"testing"
6
+
7
+	"github.com/9seconds/mtg/v2/internal/testlib"
8
+	"github.com/9seconds/mtg/v2/mtglib"
9
+	"github.com/9seconds/mtg/v2/mtglib/internal/obfuscation"
10
+	"github.com/stretchr/testify/assert"
11
+	"github.com/stretchr/testify/mock"
12
+	"github.com/stretchr/testify/require"
13
+	"github.com/stretchr/testify/suite"
14
+)
15
+
16
+type ObfuscatorTestSuite struct {
17
+	SnapshotTestSuite
18
+
19
+	secret *mtglib.Secret
20
+}
21
+
22
+func (s *ObfuscatorTestSuite) SetupSuite() {
23
+	s.SnapshotTestSuite.Setup("", "client-handshake")
24
+
25
+	secret := mtglib.GenerateSecret("hostname.com")
26
+	s.secret = &secret
27
+}
28
+
29
+func (s *ObfuscatorTestSuite) TestSnapshot() {
30
+	for name, snapshot := range s.snapshots {
31
+		s.T().Run(name, func(t *testing.T) {
32
+			obfs := obfuscation.Obfuscator{
33
+				Secret: snapshot.Secret.data,
34
+			}
35
+
36
+			connMock := &testlib.EssentialsConnMock{}
37
+
38
+			connMockReadBuffer := &bytes.Buffer{}
39
+			connMockReadBuffer.Write(snapshot.Frame.data)
40
+			connMockReadBuffer.Write(snapshot.Decrypted.Cipher.data)
41
+
42
+			connMockWriteBuffer := &bytes.Buffer{}
43
+
44
+			connMock.
45
+				On("Read", mock.AnythingOfType("[]uint8")).
46
+				Return(64, nil).
47
+				Run(func(args mock.Arguments) {
48
+					arr := args.Get(0).([]byte)
49
+					_, err := connMockReadBuffer.Read(arr)
50
+					require.NoError(t, err)
51
+				})
52
+
53
+			dc, cn, err := obfs.ReadHandshake(connMock)
54
+			assert.EqualValues(t, 2, dc)
55
+			assert.NoError(t, err)
56
+
57
+			connMock.Calls = []mock.Call{}
58
+			connMock.ExpectedCalls = []*mock.Call{}
59
+
60
+			connMock.
61
+				On("Read", mock.AnythingOfType("[]uint8")).
62
+				Return(len(snapshot.Decrypted.Cipher.data), nil).
63
+				Run(func(args mock.Arguments) {
64
+					arr := args.Get(0).([]byte)
65
+					_, err := connMockReadBuffer.Read(arr)
66
+					require.NoError(t, err)
67
+				})
68
+			connMock.
69
+				On("Write", mock.AnythingOfType("[]uint8")).
70
+				Return(len(snapshot.Encrypted.Cipher.data), nil).
71
+				Run(func(args mock.Arguments) {
72
+					arr := args.Get(0).([]byte)
73
+					_, err := connMockWriteBuffer.Write(arr)
74
+					require.NoError(t, err)
75
+				})
76
+
77
+			readBuf := make([]byte, len(snapshot.Decrypted.Text.data))
78
+			_, err = cn.Read(readBuf)
79
+			assert.NoError(t, err)
80
+			assert.Equal(t, readBuf, snapshot.Decrypted.Text.data)
81
+
82
+			_, err = cn.Write(snapshot.Encrypted.Text.data)
83
+			assert.NoError(t, err)
84
+			assert.Equal(t, connMockWriteBuffer.Bytes(), snapshot.Encrypted.Cipher.data)
85
+
86
+			connMock.AssertExpectations(t)
87
+		})
88
+	}
89
+}
90
+
91
+func TestObfuscator(t *testing.T) {
92
+	t.Parallel()
93
+	suite.Run(t, &ObfuscatorTestSuite{})
94
+}

+ 13
- 0
mtglib/internal/obfuscation/testdata/client-handshake-snapshot-4529d55776e2d427.json View File

@@ -0,0 +1,13 @@
1
+{
2
+  "secret": "NnoYmu4Y+jHBkAVO/UqOlQ",
3
+  "frame": "gDcXwaMY4RwlR+nJw+ILDr123UJHHjjE/U5pF4m/Y04AmH7lEpEL6UYRnIYDbDlOHSDxc1ToziPvNlJJh8RMow",
4
+  "dc": 2,
5
+  "encrypted": {
6
+    "text": "AQIDBAUGBwgJCg",
7
+    "cipher": "wZV3TR39l9nRoQ"
8
+  },
9
+  "decrypted": {
10
+    "text": "4wZj6mUUew",
11
+    "cipher": "YWJjZGVmZw"
12
+  }
13
+}

+ 13
- 0
mtglib/internal/obfuscation/testdata/client-handshake-snapshot-585c944d672f60a2.json View File

@@ -0,0 +1,13 @@
1
+{
2
+  "secret": "NnoYmu4Y+jHBkAVO/UqOlQ",
3
+  "frame": "M2WyxeiwIQB+ZOFxNzSNHtu9OdESkfxv3JkKFimCxUoYA3BD/Ql9nXB/OIonCKLUKCcS0VzZ2P6/+5oQ9GI8YA",
4
+  "dc": 2,
5
+  "encrypted": {
6
+    "text": "AQIDBAUGBwgJCg",
7
+    "cipher": "tzAwrCz00odERg"
8
+  },
9
+  "decrypted": {
10
+    "text": "QkIvwGQDgA",
11
+    "cipher": "YWJjZGVmZw"
12
+  }
13
+}

Loading…
Cancel
Save