Browse Source

Add required things for middlehandshake

tags/1.0^2
9seconds 6 years ago
parent
commit
1617866c24
6 changed files with 121 additions and 22 deletions
  1. 2
    3
      cli/proxy.go
  2. 1
    7
      obfuscated2/telegram_protocol.go
  3. 1
    5
      protocol/interfaces.go
  4. 5
    6
      proxy/proxy.go
  5. 1
    1
      wrappers/blockcipher.go
  6. 111
    0
      wrappers/mtproto_cipher.go

+ 2
- 3
cli/proxy.go View File

76
 	}()
76
 	}()
77
 
77
 
78
 	app := &proxy.Proxy{
78
 	app := &proxy.Proxy{
79
-		Logger:  zap.S().Named("proxy"),
80
-		Context: ctx,
79
+		Logger:              zap.S().Named("proxy"),
80
+		Context:             ctx,
81
 		ClientProtocolMaker: obfuscated2.MakeClientProtocol,
81
 		ClientProtocolMaker: obfuscated2.MakeClientProtocol,
82
-		TelegramProtocolMaker: obfuscated2.MakeTelegramProtocol,
83
 	}
82
 	}
84
 	// if len(config.C.AdTag) == 0 {
83
 	// if len(config.C.AdTag) == 0 {
85
 	// 	app.TelegramProtocolMaker = obfuscated2.MakeTelegramProtocol
84
 	// 	app.TelegramProtocolMaker = obfuscated2.MakeTelegramProtocol

+ 1
- 7
obfuscated2/telegram_protocol.go View File

10
 	"github.com/9seconds/mtg/wrappers"
10
 	"github.com/9seconds/mtg/wrappers"
11
 )
11
 )
12
 
12
 
13
-type TelegramProtocol struct{}
14
-
15
-func (t *TelegramProtocol) Handshake(req *protocol.TelegramRequest) (wrappers.Wrap, error) {
13
+func TelegramProtocol(req *protocol.TelegramRequest) (wrappers.Wrap, error) {
16
 	socket, err := telegram.Direct.Dial(req.Ctx,
14
 	socket, err := telegram.Direct.Dial(req.Ctx,
17
 		req.Cancel,
15
 		req.Cancel,
18
 		req.ClientProtocol.DC(),
16
 		req.ClientProtocol.DC(),
39
 	return wrappers.NewObfuscated2(socket, encryptor, decryptor), nil
37
 	return wrappers.NewObfuscated2(socket, encryptor, decryptor), nil
40
 }
38
 }
41
 
39
 
42
-func MakeTelegramProtocol() protocol.TelegramProtocol {
43
-	return &TelegramProtocol{}
44
-}
45
-
46
 func generateFrame(cp protocol.ClientProtocol) (fm Frame) {
40
 func generateFrame(cp protocol.ClientProtocol) (fm Frame) {
47
 	data := fm.Bytes()
41
 	data := fm.Bytes()
48
 
42
 

+ 1
- 5
protocol/interfaces.go View File

12
 	DC() conntypes.DC
12
 	DC() conntypes.DC
13
 }
13
 }
14
 
14
 
15
-type TelegramProtocol interface {
16
-	Handshake(*TelegramRequest) (wrappers.Wrap, error)
17
-}
18
-
15
+type TelegramProtocol func(*TelegramRequest) (wrappers.Wrap, error)
19
 type ClientProtocolMaker func() ClientProtocol
16
 type ClientProtocolMaker func() ClientProtocol
20
-type TelegramProtocolMaker func() TelegramProtocol

+ 5
- 6
proxy/proxy.go View File

10
 
10
 
11
 	"github.com/9seconds/mtg/config"
11
 	"github.com/9seconds/mtg/config"
12
 	"github.com/9seconds/mtg/conntypes"
12
 	"github.com/9seconds/mtg/conntypes"
13
+	"github.com/9seconds/mtg/obfuscated2"
13
 	"github.com/9seconds/mtg/protocol"
14
 	"github.com/9seconds/mtg/protocol"
14
 	"github.com/9seconds/mtg/stats"
15
 	"github.com/9seconds/mtg/stats"
15
 	"github.com/9seconds/mtg/utils"
16
 	"github.com/9seconds/mtg/utils"
19
 const directPipeBufferSize = 1024 * 1024
20
 const directPipeBufferSize = 1024 * 1024
20
 
21
 
21
 type Proxy struct {
22
 type Proxy struct {
22
-	Logger                *zap.SugaredLogger
23
-	Context               context.Context
24
-	ClientProtocolMaker   protocol.ClientProtocolMaker
25
-	TelegramProtocolMaker protocol.TelegramProtocolMaker
23
+	Logger              *zap.SugaredLogger
24
+	Context             context.Context
25
+	ClientProtocolMaker protocol.ClientProtocolMaker
26
 }
26
 }
27
 
27
 
28
 func (p *Proxy) Serve(listener net.Listener) {
28
 func (p *Proxy) Serve(listener net.Listener) {
98
 }
98
 }
99
 
99
 
100
 func (p *Proxy) acceptDirectConnection(request *protocol.TelegramRequest) error {
100
 func (p *Proxy) acceptDirectConnection(request *protocol.TelegramRequest) error {
101
-	telegramProtocol := p.TelegramProtocolMaker()
102
-	telegramConnRaw, err := telegramProtocol.Handshake(request)
101
+	telegramConnRaw, err := obfuscated2.TelegramProtocol(request)
103
 	if err != nil {
102
 	if err != nil {
104
 		return err
103
 		return err
105
 	}
104
 	}

+ 1
- 1
wrappers/blockcipher.go View File

148
 	return w.parent.RemoteAddr()
148
 	return w.parent.RemoteAddr()
149
 }
149
 }
150
 
150
 
151
-func NewBlockCipher(parent StreamReadWriteCloser, encryptor, decryptor cipher.BlockMode) StreamReadWriteCloser {
151
+func newBlockCipher(parent StreamReadWriteCloser, encryptor, decryptor cipher.BlockMode) StreamReadWriteCloser {
152
 	return &wrapperBlockCipher{
152
 	return &wrapperBlockCipher{
153
 		parent:    parent,
153
 		parent:    parent,
154
 		encryptor: encryptor,
154
 		encryptor: encryptor,

+ 111
- 0
wrappers/mtproto_cipher.go View File

1
+package wrappers
2
+
3
+import (
4
+	"bytes"
5
+	"crypto/aes"
6
+	"crypto/cipher"
7
+	"crypto/md5"
8
+	"crypto/sha1"
9
+	"encoding/binary"
10
+	"net"
11
+
12
+	"github.com/9seconds/mtg/mtproto/rpc"
13
+	"github.com/9seconds/mtg/utils"
14
+)
15
+
16
+type mtprotoCipherPurpose uint8
17
+
18
+const (
19
+	mtprotoCipherPurposeClient mtprotoCipherPurpose = iota
20
+	mtprotoCipherPurposeServer
21
+)
22
+
23
+var mtprotoEmptyIP = [4]byte{0x00, 0x00, 0x00, 0x00}
24
+
25
+func NewMiddleProxyCipher(parent StreamReadWriteCloser,
26
+	req *rpc.NonceRequest,
27
+	resp *rpc.NonceResponse,
28
+	secret []byte) StreamReadWriteCloser {
29
+	localAddr := parent.LocalAddr()
30
+	remoteAddr := parent.RemoteAddr()
31
+
32
+	encKey, encIV := mtprotoDeriveKeys(mtprotoCipherPurposeClient,
33
+		req,
34
+		resp,
35
+		localAddr,
36
+		remoteAddr,
37
+		secret)
38
+	decKey, decIV := mtprotoDeriveKeys(mtprotoCipherPurposeServer,
39
+		req,
40
+		resp,
41
+		localAddr,
42
+		remoteAddr,
43
+		secret)
44
+
45
+	enc, _ := mtprotoMakeEncrypterDecrypter(encKey, encIV)
46
+	_, dec := mtprotoMakeEncrypterDecrypter(decKey, decIV)
47
+
48
+	return newBlockCipher(parent, enc, dec)
49
+}
50
+
51
+func mtprotoDeriveKeys(purpose mtprotoCipherPurpose,
52
+	req *rpc.NonceRequest,
53
+	resp *rpc.NonceResponse,
54
+	client, remote *net.TCPAddr,
55
+	secret []byte) ([]byte, []byte) {
56
+	message := bytes.Buffer{}
57
+	message.Write(resp.Nonce)   // nolint: gosec
58
+	message.Write(req.Nonce)    // nolint: gosec
59
+	message.Write(req.CryptoTS) // nolint: gosec
60
+
61
+	clientIPv4 := mtprotoEmptyIP[:]
62
+	serverIPv4 := mtprotoEmptyIP[:]
63
+	if client.IP.To4() != nil {
64
+		clientIPv4 = utils.ReverseBytes(client.IP.To4())
65
+		serverIPv4 = utils.ReverseBytes(remote.IP.To4())
66
+	}
67
+	message.Write(serverIPv4) // nolint: gosec
68
+
69
+	var port [2]byte
70
+	binary.LittleEndian.PutUint16(port[:], uint16(client.Port))
71
+	message.Write(port[:]) // nolint: gosec
72
+
73
+	switch purpose {
74
+	case mtprotoCipherPurposeClient:
75
+		message.WriteString("CLIENT") // nolint: gosec
76
+	case mtprotoCipherPurposeServer:
77
+		message.WriteString("SERVER") // nolint: gosec
78
+	default:
79
+		panic("Unexpected cipher purpose")
80
+	}
81
+
82
+	message.Write(clientIPv4) // nolint: gosec
83
+	binary.LittleEndian.PutUint16(port[:], uint16(remote.Port))
84
+	message.Write(port[:])    // nolint: gosec
85
+	message.Write(secret)     // nolint: gosec
86
+	message.Write(resp.Nonce) // nolint: gosec
87
+
88
+	if client.IP.To4() == nil {
89
+		message.Write(client.IP.To16()) // nolint: gosec
90
+		message.Write(remote.IP.To16()) // nolint: gosec
91
+	}
92
+	message.Write(req.Nonce) // nolint: gosec
93
+
94
+	data := message.Bytes()
95
+	md5sum := md5.Sum(data[1:]) // nolint: gas
96
+	sha1sum := sha1.Sum(data)   // nolint: gosec
97
+
98
+	key := append(md5sum[:12], sha1sum[:]...)
99
+	iv := md5.Sum(data[2:]) // nolint: gas
100
+
101
+	return key, iv[:]
102
+}
103
+
104
+func mtprotoMakeEncrypterDecrypter(key, iv []byte) (cipher.BlockMode, cipher.BlockMode) {
105
+	block, err := aes.NewCipher(key)
106
+	if err != nil {
107
+		panic(err)
108
+	}
109
+
110
+	return cipher.NewCBCEncrypter(block, iv), cipher.NewCBCDecrypter(block, iv)
111
+}

Loading…
Cancel
Save