From 1617866c24868b1876b3796881c9f10cc919fa70 Mon Sep 17 00:00:00 2001 From: 9seconds Date: Tue, 10 Sep 2019 13:54:14 +0300 Subject: [PATCH] Add required things for middlehandshake --- cli/proxy.go | 5 +- obfuscated2/telegram_protocol.go | 8 +-- protocol/interfaces.go | 6 +- proxy/proxy.go | 11 ++- wrappers/blockcipher.go | 2 +- wrappers/mtproto_cipher.go | 111 +++++++++++++++++++++++++++++++ 6 files changed, 121 insertions(+), 22 deletions(-) create mode 100644 wrappers/mtproto_cipher.go diff --git a/cli/proxy.go b/cli/proxy.go index 5a85a2e..ec8df0b 100644 --- a/cli/proxy.go +++ b/cli/proxy.go @@ -76,10 +76,9 @@ func Proxy() error { }() app := &proxy.Proxy{ - Logger: zap.S().Named("proxy"), - Context: ctx, + Logger: zap.S().Named("proxy"), + Context: ctx, ClientProtocolMaker: obfuscated2.MakeClientProtocol, - TelegramProtocolMaker: obfuscated2.MakeTelegramProtocol, } // if len(config.C.AdTag) == 0 { // app.TelegramProtocolMaker = obfuscated2.MakeTelegramProtocol diff --git a/obfuscated2/telegram_protocol.go b/obfuscated2/telegram_protocol.go index b3b1a45..eda4460 100644 --- a/obfuscated2/telegram_protocol.go +++ b/obfuscated2/telegram_protocol.go @@ -10,9 +10,7 @@ import ( "github.com/9seconds/mtg/wrappers" ) -type TelegramProtocol struct{} - -func (t *TelegramProtocol) Handshake(req *protocol.TelegramRequest) (wrappers.Wrap, error) { +func TelegramProtocol(req *protocol.TelegramRequest) (wrappers.Wrap, error) { socket, err := telegram.Direct.Dial(req.Ctx, req.Cancel, req.ClientProtocol.DC(), @@ -39,10 +37,6 @@ func (t *TelegramProtocol) Handshake(req *protocol.TelegramRequest) (wrappers.Wr return wrappers.NewObfuscated2(socket, encryptor, decryptor), nil } -func MakeTelegramProtocol() protocol.TelegramProtocol { - return &TelegramProtocol{} -} - func generateFrame(cp protocol.ClientProtocol) (fm Frame) { data := fm.Bytes() diff --git a/protocol/interfaces.go b/protocol/interfaces.go index 09f2c59..a392de1 100644 --- a/protocol/interfaces.go +++ b/protocol/interfaces.go @@ -12,9 +12,5 @@ type ClientProtocol interface { DC() conntypes.DC } -type TelegramProtocol interface { - Handshake(*TelegramRequest) (wrappers.Wrap, error) -} - +type TelegramProtocol func(*TelegramRequest) (wrappers.Wrap, error) type ClientProtocolMaker func() ClientProtocol -type TelegramProtocolMaker func() TelegramProtocol diff --git a/proxy/proxy.go b/proxy/proxy.go index e11e001..b42cd60 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -10,6 +10,7 @@ import ( "github.com/9seconds/mtg/config" "github.com/9seconds/mtg/conntypes" + "github.com/9seconds/mtg/obfuscated2" "github.com/9seconds/mtg/protocol" "github.com/9seconds/mtg/stats" "github.com/9seconds/mtg/utils" @@ -19,10 +20,9 @@ import ( const directPipeBufferSize = 1024 * 1024 type Proxy struct { - Logger *zap.SugaredLogger - Context context.Context - ClientProtocolMaker protocol.ClientProtocolMaker - TelegramProtocolMaker protocol.TelegramProtocolMaker + Logger *zap.SugaredLogger + Context context.Context + ClientProtocolMaker protocol.ClientProtocolMaker } func (p *Proxy) Serve(listener net.Listener) { @@ -98,8 +98,7 @@ func (p *Proxy) accept(conn net.Conn) { } func (p *Proxy) acceptDirectConnection(request *protocol.TelegramRequest) error { - telegramProtocol := p.TelegramProtocolMaker() - telegramConnRaw, err := telegramProtocol.Handshake(request) + telegramConnRaw, err := obfuscated2.TelegramProtocol(request) if err != nil { return err } diff --git a/wrappers/blockcipher.go b/wrappers/blockcipher.go index c6a00b5..4554515 100644 --- a/wrappers/blockcipher.go +++ b/wrappers/blockcipher.go @@ -148,7 +148,7 @@ func (w *wrapperBlockCipher) RemoteAddr() *net.TCPAddr { return w.parent.RemoteAddr() } -func NewBlockCipher(parent StreamReadWriteCloser, encryptor, decryptor cipher.BlockMode) StreamReadWriteCloser { +func newBlockCipher(parent StreamReadWriteCloser, encryptor, decryptor cipher.BlockMode) StreamReadWriteCloser { return &wrapperBlockCipher{ parent: parent, encryptor: encryptor, diff --git a/wrappers/mtproto_cipher.go b/wrappers/mtproto_cipher.go new file mode 100644 index 0000000..e297d31 --- /dev/null +++ b/wrappers/mtproto_cipher.go @@ -0,0 +1,111 @@ +package wrappers + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/md5" + "crypto/sha1" + "encoding/binary" + "net" + + "github.com/9seconds/mtg/mtproto/rpc" + "github.com/9seconds/mtg/utils" +) + +type mtprotoCipherPurpose uint8 + +const ( + mtprotoCipherPurposeClient mtprotoCipherPurpose = iota + mtprotoCipherPurposeServer +) + +var mtprotoEmptyIP = [4]byte{0x00, 0x00, 0x00, 0x00} + +func NewMiddleProxyCipher(parent StreamReadWriteCloser, + req *rpc.NonceRequest, + resp *rpc.NonceResponse, + secret []byte) StreamReadWriteCloser { + localAddr := parent.LocalAddr() + remoteAddr := parent.RemoteAddr() + + encKey, encIV := mtprotoDeriveKeys(mtprotoCipherPurposeClient, + req, + resp, + localAddr, + remoteAddr, + secret) + decKey, decIV := mtprotoDeriveKeys(mtprotoCipherPurposeServer, + req, + resp, + localAddr, + remoteAddr, + secret) + + enc, _ := mtprotoMakeEncrypterDecrypter(encKey, encIV) + _, dec := mtprotoMakeEncrypterDecrypter(decKey, decIV) + + return newBlockCipher(parent, enc, dec) +} + +func mtprotoDeriveKeys(purpose mtprotoCipherPurpose, + req *rpc.NonceRequest, + resp *rpc.NonceResponse, + client, remote *net.TCPAddr, + secret []byte) ([]byte, []byte) { + message := bytes.Buffer{} + message.Write(resp.Nonce) // nolint: gosec + message.Write(req.Nonce) // nolint: gosec + message.Write(req.CryptoTS) // nolint: gosec + + clientIPv4 := mtprotoEmptyIP[:] + serverIPv4 := mtprotoEmptyIP[:] + if client.IP.To4() != nil { + clientIPv4 = utils.ReverseBytes(client.IP.To4()) + serverIPv4 = utils.ReverseBytes(remote.IP.To4()) + } + message.Write(serverIPv4) // nolint: gosec + + var port [2]byte + binary.LittleEndian.PutUint16(port[:], uint16(client.Port)) + message.Write(port[:]) // nolint: gosec + + switch purpose { + case mtprotoCipherPurposeClient: + message.WriteString("CLIENT") // nolint: gosec + case mtprotoCipherPurposeServer: + message.WriteString("SERVER") // nolint: gosec + default: + panic("Unexpected cipher purpose") + } + + message.Write(clientIPv4) // nolint: gosec + binary.LittleEndian.PutUint16(port[:], uint16(remote.Port)) + message.Write(port[:]) // nolint: gosec + message.Write(secret) // nolint: gosec + message.Write(resp.Nonce) // nolint: gosec + + if client.IP.To4() == nil { + message.Write(client.IP.To16()) // nolint: gosec + message.Write(remote.IP.To16()) // nolint: gosec + } + message.Write(req.Nonce) // nolint: gosec + + data := message.Bytes() + md5sum := md5.Sum(data[1:]) // nolint: gas + sha1sum := sha1.Sum(data) // nolint: gosec + + key := append(md5sum[:12], sha1sum[:]...) + iv := md5.Sum(data[2:]) // nolint: gas + + return key, iv[:] +} + +func mtprotoMakeEncrypterDecrypter(key, iv []byte) (cipher.BlockMode, cipher.BlockMode) { + block, err := aes.NewCipher(key) + if err != nil { + panic(err) + } + + return cipher.NewCBCEncrypter(block, iv), cipher.NewCBCDecrypter(block, iv) +}