mirror of
https://github.com/ScuroNeko/mtg.git
synced 2026-08-31 15:54:03 +03:00
Direct proxy works
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
package obfuscated2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/juju/errors"
|
||||
|
||||
"github.com/9seconds/mtg/antireplay"
|
||||
"github.com/9seconds/mtg/config"
|
||||
"github.com/9seconds/mtg/conntypes"
|
||||
"github.com/9seconds/mtg/protocol"
|
||||
"github.com/9seconds/mtg/utils"
|
||||
"github.com/9seconds/mtg/wrappers"
|
||||
)
|
||||
|
||||
const clientProtocolHandshakeTimeout = 10 * time.Second
|
||||
|
||||
type ClientProtocol struct {
|
||||
protocol.BaseProtocol
|
||||
}
|
||||
|
||||
func (c *ClientProtocol) Handshake(socket wrappers.StreamReadWriteCloser) (wrappers.StreamReadWriteCloser, error) {
|
||||
fm, err := c.ReadFrame(socket)
|
||||
if err != nil {
|
||||
return nil, errors.Annotate(err, "Cannot make client handshake")
|
||||
}
|
||||
|
||||
decHasher := sha256.New()
|
||||
decHasher.Write(fm.Key()) // nolint: errcheck
|
||||
decHasher.Write(config.C.Secret) // nolint: errcheck
|
||||
decryptor := utils.MakeStreamCipher(decHasher.Sum(nil), fm.IV())
|
||||
|
||||
invertedFrame := fm.Invert()
|
||||
encHasher := sha256.New()
|
||||
encHasher.Write(invertedFrame.Key()) // nolint: errcheck
|
||||
encHasher.Write(config.C.Secret) // nolint: errcheck
|
||||
encryptor := utils.MakeStreamCipher(encHasher.Sum(nil), invertedFrame.IV())
|
||||
|
||||
decryptedFrame := Frame{}
|
||||
decryptor.XORKeyStream(decryptedFrame.Bytes(), fm.Bytes())
|
||||
|
||||
magic := decryptedFrame.Magic()
|
||||
switch {
|
||||
case bytes.Equal(magic, conntypes.ConnectionTagAbridged):
|
||||
c.ConnectionType = conntypes.ConnectionTypeAbridged
|
||||
case bytes.Equal(magic, conntypes.ConnectionTagIntermediate):
|
||||
c.ConnectionType = conntypes.ConnectionTypeIntermediate
|
||||
case bytes.Equal(magic, conntypes.ConnectionTagSecure):
|
||||
c.ConnectionType = conntypes.ConnectionTypeSecure
|
||||
default:
|
||||
return nil, errors.New("Unknown connection type")
|
||||
}
|
||||
|
||||
c.ConnectionProtocol = conntypes.ConnectionProtocolIPv4
|
||||
if socket.LocalAddr().IP.To4() == nil {
|
||||
c.ConnectionProtocol = conntypes.ConnectionProtocolIPv6
|
||||
}
|
||||
|
||||
buf := bytes.NewReader(decryptedFrame.DC())
|
||||
if err := binary.Read(buf, binary.LittleEndian, &c.DC); err != nil {
|
||||
c.DC = conntypes.DCDefaultIdx
|
||||
}
|
||||
|
||||
antiReplayKey := decryptedFrame.Unique()
|
||||
if antireplay.Has(antiReplayKey) {
|
||||
return nil, errors.New("Replay attack is detected")
|
||||
}
|
||||
antireplay.Add(antiReplayKey)
|
||||
|
||||
return wrappers.NewObfuscated2(socket, encryptor, decryptor), nil
|
||||
}
|
||||
|
||||
func (c *ClientProtocol) ReadFrame(socket wrappers.StreamReader) (fm Frame, err error) {
|
||||
if _, err = io.ReadFull(handshakeReader{socket}, fm.Bytes()); err != nil {
|
||||
err = errors.Annotate(err, "Cannot extract obfuscated2 frame")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type handshakeReader struct {
|
||||
parent wrappers.StreamReader
|
||||
}
|
||||
|
||||
func (h handshakeReader) Read(p []byte) (int, error) {
|
||||
return h.parent.ReadTimeout(p, clientProtocolHandshakeTimeout)
|
||||
}
|
||||
|
||||
func MakeClientProtocol() protocol.ClientProtocol {
|
||||
return &ClientProtocol{}
|
||||
}
|
||||
+28
-95
@@ -1,17 +1,5 @@
|
||||
package obfuscated2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
|
||||
"github.com/juju/errors"
|
||||
|
||||
"github.com/9seconds/mtg/mtproto"
|
||||
)
|
||||
|
||||
// [frameOffsetFirst:frameOffsetKey:frameOffsetIV:frameOffsetMagic:frameOffsetDC:frameOffsetEnd]
|
||||
const (
|
||||
frameLenKey = 32
|
||||
frameLenIV = 16
|
||||
@@ -24,98 +12,43 @@ const (
|
||||
frameOffsetMagic = frameOffsetIV + frameLenMagic
|
||||
frameOffsetDC = frameOffsetMagic + frameLenDC
|
||||
|
||||
FrameLen = 64
|
||||
frameLen = 64
|
||||
)
|
||||
|
||||
// Frame represents handshake frame. Telegram sends 64 bytes of obfuscated2
|
||||
// initialization data first.
|
||||
// https://blog.susanka.eu/how-telegram-obfuscates-its-mtproto-traffic/
|
||||
type Frame []byte
|
||||
|
||||
// Key returns AES encryption key.
|
||||
func (f Frame) Key() []byte {
|
||||
return f[frameOffsetFirst:frameOffsetKey]
|
||||
// [frameOffsetFirst:frameOffsetKey:frameOffsetIV:frameOffsetMagic:frameOffsetDC:frameOffsetEnd]
|
||||
type Frame struct {
|
||||
data [frameLen]byte
|
||||
}
|
||||
|
||||
// IV returns AES encryption initialization vector
|
||||
func (f Frame) IV() []byte {
|
||||
return f[frameOffsetKey:frameOffsetIV]
|
||||
func (f *Frame) Bytes() []byte {
|
||||
return f.data[:]
|
||||
}
|
||||
|
||||
// Magic returns magic bytes from last 8 bytes of frame. Telegram checks
|
||||
// for values there. If after decryption magic is not as expected,
|
||||
// connection considered as failed.
|
||||
func (f Frame) Magic() []byte {
|
||||
return f[frameOffsetIV:frameOffsetMagic]
|
||||
func (f *Frame) Key() []byte {
|
||||
return f.data[frameOffsetFirst:frameOffsetKey]
|
||||
}
|
||||
|
||||
// DC returns number of datacenter IP client wants to use.
|
||||
func (f Frame) DC() (n int16) {
|
||||
buf := bytes.NewReader(f[frameOffsetMagic:frameOffsetDC])
|
||||
if err := binary.Read(buf, binary.LittleEndian, &n); err != nil {
|
||||
n = 1
|
||||
func (f *Frame) IV() []byte {
|
||||
return f.data[frameOffsetKey:frameOffsetIV]
|
||||
}
|
||||
|
||||
func (f *Frame) Magic() []byte {
|
||||
return f.data[frameOffsetIV:frameOffsetMagic]
|
||||
}
|
||||
|
||||
func (f *Frame) DC() []byte {
|
||||
return f.data[frameOffsetMagic:frameOffsetDC]
|
||||
}
|
||||
|
||||
func (f *Frame) Unique() []byte {
|
||||
return f.data[frameOffsetFirst:frameOffsetDC]
|
||||
}
|
||||
|
||||
func (f *Frame) Invert() (nf Frame) {
|
||||
nf = *f
|
||||
for i := 0; i < frameLenKey+frameLenIV; i++ {
|
||||
nf.data[frameOffsetFirst+i] = f.data[frameOffsetIV-1-i]
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ConnectionType identifies connection type of the handshake frame.
|
||||
func (f Frame) ConnectionType() (mtproto.ConnectionType, error) {
|
||||
return mtproto.ConnectionTagFromHandshake(f.Magic())
|
||||
}
|
||||
|
||||
// Invert inverts frame for extracting encryption keys. Pkease check that link:
|
||||
// https://blog.susanka.eu/how-telegram-obfuscates-its-mtproto-traffic/
|
||||
func (f Frame) Invert() Frame {
|
||||
reversed := make(Frame, FrameLen)
|
||||
copy(reversed, f)
|
||||
|
||||
for i := 0; i < frameLenKey+frameLenIV; i++ {
|
||||
reversed[frameOffsetFirst+i] = f[frameOffsetIV-1-i]
|
||||
}
|
||||
|
||||
return reversed
|
||||
}
|
||||
|
||||
// ExtractFrame extracts exact obfuscated2 handshake frame from given reader.
|
||||
func ExtractFrame(conn io.Reader) (Frame, error) {
|
||||
frame := make(Frame, FrameLen)
|
||||
buf := bytes.NewBuffer(frame)
|
||||
buf.Reset()
|
||||
|
||||
if _, err := io.CopyN(buf, conn, FrameLen); err != nil {
|
||||
return nil, errors.Annotate(err, "Cannot extract obfuscated header")
|
||||
}
|
||||
copy(frame, buf.Bytes())
|
||||
|
||||
return frame, nil
|
||||
}
|
||||
|
||||
func generateFrame(connectionType mtproto.ConnectionType) Frame {
|
||||
frame := make(Frame, FrameLen)
|
||||
|
||||
for {
|
||||
if _, err := rand.Read(frame); err != nil {
|
||||
continue
|
||||
}
|
||||
if frame[0] == 0xef {
|
||||
continue
|
||||
}
|
||||
|
||||
val := (uint32(frame[3]) << 24) | (uint32(frame[2]) << 16) | (uint32(frame[1]) << 8) | uint32(frame[0])
|
||||
if val == 0x44414548 || val == 0x54534f50 || val == 0x20544547 || val == 0x4954504f || val == 0xeeeeeeee {
|
||||
continue
|
||||
}
|
||||
|
||||
val = (uint32(frame[7]) << 24) | (uint32(frame[6]) << 16) | (uint32(frame[5]) << 8) | uint32(frame[4])
|
||||
if val == 0x00000000 {
|
||||
continue
|
||||
}
|
||||
|
||||
// error has to be checked before calling this function
|
||||
tag, _ := connectionType.Tag() // nolint: errcheck, gosec
|
||||
copy(frame.Magic(), tag)
|
||||
|
||||
return frame
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
package obfuscated2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/9seconds/mtg/mtproto"
|
||||
)
|
||||
|
||||
func TestFrameKey(t *testing.T) {
|
||||
toCompare := make([]byte, 32)
|
||||
for i := 0; i < 32; i++ {
|
||||
toCompare[i] = byte(1)
|
||||
}
|
||||
|
||||
assert.Equal(t, toCompare, makeFrame().Key())
|
||||
}
|
||||
|
||||
func TestFrameIV(t *testing.T) {
|
||||
toCompare := make([]byte, 16)
|
||||
for i := 0; i < 16; i++ {
|
||||
toCompare[i] = byte(2)
|
||||
}
|
||||
|
||||
assert.Equal(t, toCompare, makeFrame().IV())
|
||||
}
|
||||
|
||||
func TestFrameMagic(t *testing.T) {
|
||||
toCompare := make([]byte, 4)
|
||||
for i := 0; i < 4; i++ {
|
||||
toCompare[i] = 0xee
|
||||
}
|
||||
|
||||
assert.Equal(t, toCompare, makeFrame().Magic())
|
||||
}
|
||||
|
||||
func TestFrameDC(t *testing.T) {
|
||||
assert.Equal(t, int16(771), makeFrame().DC())
|
||||
}
|
||||
|
||||
func TestFrameValid(t *testing.T) {
|
||||
frame := makeFrame()
|
||||
connType, err := frame.ConnectionType()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, connType, mtproto.ConnectionTypeIntermediate)
|
||||
|
||||
frame[8+32+16+2] = byte(3)
|
||||
_, err = frame.ConnectionType()
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestFrameDoubleInvert(t *testing.T) {
|
||||
frame := makeFrame()
|
||||
assert.True(t, bytes.Equal(frame, frame.Invert().Invert()))
|
||||
}
|
||||
|
||||
func TestFrameInvert(t *testing.T) {
|
||||
frame := makeFrame()
|
||||
reversed := frame.Invert()
|
||||
|
||||
assert.Exactly(t, frame[:8], reversed[:8])
|
||||
assert.Exactly(t, frame[56:], reversed[56:])
|
||||
|
||||
toCompare := make([]byte, 48)
|
||||
for i := 0; i < 48; i++ {
|
||||
toCompare[i] = frame[55-i]
|
||||
}
|
||||
assert.Equal(t, []byte(reversed[8:56]), toCompare)
|
||||
}
|
||||
|
||||
func TestFrameGenerateValid(t *testing.T) {
|
||||
validTests := []mtproto.ConnectionType{
|
||||
mtproto.ConnectionTypeIntermediate,
|
||||
mtproto.ConnectionTypeAbridged,
|
||||
}
|
||||
for _, test := range validTests {
|
||||
t.Run(strconv.Itoa(int(test)), func(tt *testing.T) {
|
||||
frame := generateFrame(test) // nolint: scopelint
|
||||
conType, err := frame.ConnectionType()
|
||||
assert.Nil(tt, err)
|
||||
assert.Equal(tt, conType, test) // nolint: scopelint
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func makeFrame() Frame {
|
||||
f := make(Frame, FrameLen)
|
||||
|
||||
for i := 8; i < (8 + 32); i++ {
|
||||
f[i] = byte(1)
|
||||
}
|
||||
for i := (8 + 32); i < (8 + 32 + 16); i++ {
|
||||
f[i] = byte(2)
|
||||
}
|
||||
for i := (8 + 32 + 16); i < (8 + 32 + 16 + 4); i++ {
|
||||
f[i] = 0xee
|
||||
}
|
||||
for i := (8 + 32 + 16 + 4); i < (8 + 32 + 16 + 4 + 2); i++ {
|
||||
f[i] = byte(3)
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package obfuscated2
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/sha256"
|
||||
|
||||
"github.com/juju/errors"
|
||||
|
||||
"github.com/9seconds/mtg/mtproto"
|
||||
)
|
||||
|
||||
// Obfuscated2 contains AES CTR encryption and decryption streams
|
||||
// for telegram connection.
|
||||
type Obfuscated2 struct {
|
||||
Decryptor cipher.Stream
|
||||
Encryptor cipher.Stream
|
||||
}
|
||||
|
||||
// ParseObfuscated2ClientFrame parses client frame. Please check this link for
|
||||
// details: http://telegra.ph/telegram-blocks-wtf-05-26
|
||||
//
|
||||
// Beware, link above is in russian.
|
||||
func ParseObfuscated2ClientFrame(secret []byte, frame Frame) (*Obfuscated2, *mtproto.ConnectionOpts, error) {
|
||||
decHasher := sha256.New()
|
||||
decHasher.Write(frame.Key()) // nolint: errcheck, gosec
|
||||
decHasher.Write(secret) // nolint: errcheck, gosec
|
||||
decryptor := makeStreamCipher(decHasher.Sum(nil), frame.IV())
|
||||
|
||||
invertedFrame := frame.Invert()
|
||||
encHasher := sha256.New()
|
||||
encHasher.Write(invertedFrame.Key()) // nolint: errcheck, gosec
|
||||
encHasher.Write(secret) // nolint: errcheck, gosec
|
||||
encryptor := makeStreamCipher(encHasher.Sum(nil), invertedFrame.IV())
|
||||
|
||||
decryptedFrame := make(Frame, FrameLen)
|
||||
decryptor.XORKeyStream(decryptedFrame, frame)
|
||||
connType, err := decryptedFrame.ConnectionType()
|
||||
if err != nil {
|
||||
return nil, nil, errors.Annotate(err, "Unknown protocol")
|
||||
}
|
||||
|
||||
obfs := &Obfuscated2{
|
||||
Decryptor: decryptor,
|
||||
Encryptor: encryptor,
|
||||
}
|
||||
connOpts := &mtproto.ConnectionOpts{
|
||||
DC: decryptedFrame.DC(),
|
||||
ConnectionType: connType,
|
||||
}
|
||||
|
||||
return obfs, connOpts, nil
|
||||
}
|
||||
|
||||
// MakeTelegramObfuscated2Frame creates new handshake frame to send to
|
||||
// Telegram.
|
||||
// https://blog.susanka.eu/how-telegram-obfuscates-its-mtproto-traffic/
|
||||
func MakeTelegramObfuscated2Frame(opts *mtproto.ConnectionOpts) (*Obfuscated2, Frame) {
|
||||
frame := generateFrame(opts.ConnectionType)
|
||||
|
||||
encryptor := makeStreamCipher(frame.Key(), frame.IV())
|
||||
decryptorFrame := frame.Invert()
|
||||
decryptor := makeStreamCipher(decryptorFrame.Key(), decryptorFrame.IV())
|
||||
|
||||
copyFrame := make(Frame, FrameLen)
|
||||
copy(copyFrame[:frameOffsetIV], frame[:frameOffsetIV])
|
||||
encryptor.XORKeyStream(frame, frame)
|
||||
copy(frame[:frameOffsetIV], copyFrame[:frameOffsetIV])
|
||||
|
||||
obfs := &Obfuscated2{
|
||||
Decryptor: decryptor,
|
||||
Encryptor: encryptor,
|
||||
}
|
||||
|
||||
return obfs, frame
|
||||
}
|
||||
|
||||
func makeStreamCipher(key, iv []byte) cipher.Stream {
|
||||
block, _ := aes.NewCipher(key) // nolint: gosec
|
||||
return cipher.NewCTR(block, iv)
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
package obfuscated2
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/9seconds/mtg/mtproto"
|
||||
)
|
||||
|
||||
func TestObfs2TelegramFrameDecrypt(t *testing.T) {
|
||||
connOpts := &mtproto.ConnectionOpts{
|
||||
DC: 1,
|
||||
ConnectionType: mtproto.ConnectionTypeIntermediate,
|
||||
}
|
||||
_, frame := MakeTelegramObfuscated2Frame(connOpts)
|
||||
decryptor := makeStreamCipher(frame.Key(), frame.IV())
|
||||
|
||||
decrypted := make(Frame, FrameLen)
|
||||
decryptor.XORKeyStream(decrypted, frame)
|
||||
|
||||
_, err := decrypted.ConnectionType()
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestObfs2TelegramDecryptEncryptDecrypt(t *testing.T) {
|
||||
connOpts := &mtproto.ConnectionOpts{
|
||||
DC: 1,
|
||||
ConnectionType: mtproto.ConnectionTypeIntermediate,
|
||||
}
|
||||
obfs2, frame := MakeTelegramObfuscated2Frame(connOpts)
|
||||
inverted := frame.Invert()
|
||||
encryptor := makeStreamCipher(inverted.Key(), inverted.IV())
|
||||
|
||||
data := []byte{1, 2, 3}
|
||||
encrypted := make([]byte, 3)
|
||||
encryptor.XORKeyStream(encrypted, data)
|
||||
decrypted := make([]byte, 3)
|
||||
obfs2.Decryptor.XORKeyStream(decrypted, encrypted)
|
||||
|
||||
assert.Equal(t, data, decrypted)
|
||||
}
|
||||
|
||||
func TestObfs2Full(t *testing.T) {
|
||||
secret := []byte{1, 2, 3, 4, 5}
|
||||
|
||||
clientFrame := generateFrame(mtproto.ConnectionTypeIntermediate)
|
||||
clientHasher := sha256.New()
|
||||
clientHasher.Write(clientFrame.Key()) // nolint: errcheck, gosec
|
||||
clientHasher.Write(secret) // nolint: errcheck, gosec
|
||||
clientKey := clientHasher.Sum(nil)
|
||||
|
||||
encryptor := makeStreamCipher(clientKey, clientFrame.IV())
|
||||
encrypted := make(Frame, FrameLen)
|
||||
encryptor.XORKeyStream(encrypted, clientFrame)
|
||||
copy(encrypted[:56], clientFrame[:56])
|
||||
|
||||
invertedClientFrame := clientFrame.Invert()
|
||||
clientHasher = sha256.New()
|
||||
clientHasher.Write(invertedClientFrame.Key()) // nolint: errcheck, gosec
|
||||
clientHasher.Write(secret) // nolint: errcheck, gosec
|
||||
invertedClientKey := clientHasher.Sum(nil)
|
||||
clientDecryptor := makeStreamCipher(invertedClientKey, invertedClientFrame.IV())
|
||||
|
||||
clientObfs, _, err := ParseObfuscated2ClientFrame(secret, encrypted)
|
||||
assert.Nil(t, err)
|
||||
|
||||
connOpts := &mtproto.ConnectionOpts{
|
||||
DC: 1,
|
||||
ConnectionType: mtproto.ConnectionTypeIntermediate,
|
||||
}
|
||||
tgObfs, tgFrame := MakeTelegramObfuscated2Frame(connOpts)
|
||||
tgDecryptor := makeStreamCipher(tgFrame.Key(), tgFrame.IV())
|
||||
decrypted := make(Frame, FrameLen)
|
||||
tgDecryptor.XORKeyStream(decrypted, tgFrame)
|
||||
_, err = decrypted.ConnectionType()
|
||||
assert.Nil(t, err)
|
||||
|
||||
tgInvertedFrame := tgFrame.Invert()
|
||||
tgEncryptor := makeStreamCipher(tgInvertedFrame.Key(), tgInvertedFrame.IV())
|
||||
|
||||
message := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}
|
||||
tgEncryptedMessage := make([]byte, len(message))
|
||||
tgEncryptor.XORKeyStream(tgEncryptedMessage, message)
|
||||
|
||||
tgEncDecryptedMessage := make([]byte, len(tgEncryptedMessage))
|
||||
tgObfs.Decryptor.XORKeyStream(tgEncDecryptedMessage, tgEncryptedMessage)
|
||||
assert.Equal(t, message, tgEncDecryptedMessage)
|
||||
|
||||
clientEncryptedMessage := make([]byte, len(tgEncDecryptedMessage))
|
||||
clientObfs.Encryptor.XORKeyStream(clientEncryptedMessage, tgEncDecryptedMessage)
|
||||
finalMessage := make([]byte, len(clientEncryptedMessage))
|
||||
clientDecryptor.XORKeyStream(finalMessage, clientEncryptedMessage)
|
||||
|
||||
assert.Equal(t, finalMessage, message)
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package obfuscated2
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
|
||||
"github.com/juju/errors"
|
||||
|
||||
"github.com/9seconds/mtg/protocol"
|
||||
"github.com/9seconds/mtg/telegram"
|
||||
"github.com/9seconds/mtg/utils"
|
||||
"github.com/9seconds/mtg/wrappers"
|
||||
)
|
||||
|
||||
type TelegramProtocol struct {
|
||||
protocol.BaseProtocol
|
||||
|
||||
dialer telegram.Telegram
|
||||
}
|
||||
|
||||
func (t *TelegramProtocol) Handshake(req *protocol.TelegramRequest) (wrappers.Wrap, error) {
|
||||
socket, err := t.dialer.Dial(req.Ctx,
|
||||
req.Cancel,
|
||||
req.ClientProtocol.GetDC(),
|
||||
req.ClientProtocol.GetConnectionProtocol())
|
||||
if err != nil {
|
||||
return nil, errors.Annotate(err, "Cannot dial to Telegram")
|
||||
}
|
||||
fm := generateFrame(req.ClientProtocol)
|
||||
data := fm.Bytes()
|
||||
|
||||
encryptor := utils.MakeStreamCipher(fm.Key(), fm.IV())
|
||||
decryptedFrame := fm.Invert()
|
||||
decryptor := utils.MakeStreamCipher(decryptedFrame.Key(), decryptedFrame.IV())
|
||||
|
||||
copyFrame := make([]byte, frameLen)
|
||||
copy(copyFrame[:frameOffsetIV], data[:frameOffsetIV])
|
||||
encryptor.XORKeyStream(data, data)
|
||||
copy(data[:frameOffsetIV], copyFrame[:frameOffsetIV])
|
||||
|
||||
if _, err := socket.Write(data); err != nil {
|
||||
return nil, errors.Annotate(err, "Cannot write handshate frame to Telegram")
|
||||
}
|
||||
|
||||
return wrappers.NewObfuscated2(socket, encryptor, decryptor), nil
|
||||
}
|
||||
|
||||
func MakeTelegramProtocol(dialer telegram.Telegram) protocol.TelegramProtocol {
|
||||
return &TelegramProtocol{
|
||||
dialer: dialer,
|
||||
}
|
||||
}
|
||||
|
||||
func generateFrame(cp protocol.ClientProtocol) (fm Frame) {
|
||||
data := fm.Bytes()
|
||||
|
||||
for {
|
||||
if _, err := rand.Read(data); err != nil {
|
||||
continue
|
||||
}
|
||||
if data[0] == 0xef {
|
||||
continue
|
||||
}
|
||||
|
||||
val := (uint32(data[3]) << 24) | (uint32(data[2]) << 16) | (uint32(data[1]) << 8) | uint32(data[0])
|
||||
if val == 0x44414548 || val == 0x54534f50 || val == 0x20544547 || val == 0x4954504f || val == 0xeeeeeeee {
|
||||
continue
|
||||
}
|
||||
|
||||
val = (uint32(data[7]) << 24) | (uint32(data[6]) << 16) | (uint32(data[5]) << 8) | uint32(data[4])
|
||||
if val == 0x00000000 {
|
||||
continue
|
||||
}
|
||||
|
||||
copy(fm.Magic(), cp.GetConnectionType().Tag())
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user