mirror of
https://github.com/ScuroNeko/mtg.git
synced 2026-09-02 16:31:56 +03:00
Remove frame pool for obfuscated2 frames
This commit is contained in:
@@ -29,7 +29,6 @@ func DirectInit(conn net.Conn, conf *config.Config) (*mtproto.ConnectionOpts, io
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, errors.Annotate(err, "Cannot extract frame")
|
return nil, nil, errors.Annotate(err, "Cannot extract frame")
|
||||||
}
|
}
|
||||||
defer obfuscated2.ReturnFrame(frame)
|
|
||||||
|
|
||||||
obfs2, connOpts, err := obfuscated2.ParseObfuscated2ClientFrame(conf.Secret, frame)
|
obfs2, connOpts, err := obfuscated2.ParseObfuscated2ClientFrame(conf.Secret, frame)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+15
-17
@@ -66,57 +66,55 @@ func (f Frame) ConnectionType() (mtproto.ConnectionType, error) {
|
|||||||
|
|
||||||
// Invert inverts frame for extracting encryption keys. Pkease check that link:
|
// Invert inverts frame for extracting encryption keys. Pkease check that link:
|
||||||
// https://blog.susanka.eu/how-telegram-obfuscates-its-mtproto-traffic/
|
// https://blog.susanka.eu/how-telegram-obfuscates-its-mtproto-traffic/
|
||||||
func (f Frame) Invert() *Frame {
|
func (f Frame) Invert() Frame {
|
||||||
reversed := MakeFrame()
|
reversed := make(Frame, FrameLen)
|
||||||
copy(*reversed, f)
|
copy(reversed, f)
|
||||||
|
|
||||||
for i := 0; i < frameLenKey+frameLenIV; i++ {
|
for i := 0; i < frameLenKey+frameLenIV; i++ {
|
||||||
(*reversed)[frameOffsetFirst+i] = f[frameOffsetIV-1-i]
|
reversed[frameOffsetFirst+i] = f[frameOffsetIV-1-i]
|
||||||
}
|
}
|
||||||
|
|
||||||
return reversed
|
return reversed
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExtractFrame extracts exact obfuscated2 handshake frame from given reader.
|
// ExtractFrame extracts exact obfuscated2 handshake frame from given reader.
|
||||||
func ExtractFrame(conn io.Reader) (*Frame, error) {
|
func ExtractFrame(conn io.Reader) (Frame, error) {
|
||||||
frame := MakeFrame()
|
frame := make(Frame, FrameLen)
|
||||||
buf := bytes.NewBuffer(*frame)
|
buf := bytes.NewBuffer(frame)
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
|
|
||||||
if _, err := io.CopyN(buf, conn, FrameLen); err != nil {
|
if _, err := io.CopyN(buf, conn, FrameLen); err != nil {
|
||||||
ReturnFrame(frame)
|
|
||||||
return nil, errors.Annotate(err, "Cannot extract obfuscated header")
|
return nil, errors.Annotate(err, "Cannot extract obfuscated header")
|
||||||
}
|
}
|
||||||
copy(*frame, buf.Bytes())
|
copy(frame, buf.Bytes())
|
||||||
|
|
||||||
return frame, nil
|
return frame, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateFrame(connectionType mtproto.ConnectionType) *Frame {
|
func generateFrame(connectionType mtproto.ConnectionType) Frame {
|
||||||
frame := MakeFrame()
|
frame := make(Frame, FrameLen)
|
||||||
data := *frame
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if _, err := rand.Read(data); err != nil {
|
if _, err := rand.Read(frame); err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if data[0] == 0xef {
|
if frame[0] == 0xef {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
val := (uint32(data[3]) << 24) | (uint32(data[2]) << 16) | (uint32(data[1]) << 8) | uint32(data[0])
|
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 {
|
if val == 0x44414548 || val == 0x54534f50 || val == 0x20544547 || val == 0x4954504f || val == 0xeeeeeeee {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
val = (uint32(data[7]) << 24) | (uint32(data[6]) << 16) | (uint32(data[5]) << 8) | uint32(data[4])
|
val = (uint32(frame[7]) << 24) | (uint32(frame[6]) << 16) | (uint32(frame[5]) << 8) | uint32(frame[4])
|
||||||
if val == 0x00000000 {
|
if val == 0x00000000 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// error has to be checked before calling this function
|
// error has to be checked before calling this function
|
||||||
tag, _ := connectionType.Tag() // nolint: errcheck
|
tag, _ := connectionType.Tag() // nolint: errcheck
|
||||||
copy(data.Magic(), tag)
|
copy(frame.Magic(), tag)
|
||||||
|
|
||||||
return frame
|
return frame
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
package obfuscated2
|
|
||||||
|
|
||||||
import "sync"
|
|
||||||
|
|
||||||
var framePool sync.Pool
|
|
||||||
|
|
||||||
// MakeFrame returns new pointer to the handshake frame.
|
|
||||||
func MakeFrame() *Frame {
|
|
||||||
return framePool.Get().(*Frame)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReturnFrame returns pointer to the handshake frame back to the pool.
|
|
||||||
func ReturnFrame(f *Frame) {
|
|
||||||
framePool.Put(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
framePool = sync.Pool{
|
|
||||||
New: func() interface{} {
|
|
||||||
data := make(Frame, FrameLen)
|
|
||||||
return &data
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -54,21 +54,21 @@ func TestFrameValid(t *testing.T) {
|
|||||||
|
|
||||||
func TestFrameDoubleInvert(t *testing.T) {
|
func TestFrameDoubleInvert(t *testing.T) {
|
||||||
frame := makeFrame()
|
frame := makeFrame()
|
||||||
assert.True(t, bytes.Equal(frame, *frame.Invert().Invert()))
|
assert.True(t, bytes.Equal(frame, frame.Invert().Invert()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFrameInvert(t *testing.T) {
|
func TestFrameInvert(t *testing.T) {
|
||||||
frame := makeFrame()
|
frame := makeFrame()
|
||||||
reversed := frame.Invert()
|
reversed := frame.Invert()
|
||||||
|
|
||||||
assert.Exactly(t, frame[:8], (*reversed)[:8])
|
assert.Exactly(t, frame[:8], reversed[:8])
|
||||||
assert.Exactly(t, frame[56:], (*reversed)[56:])
|
assert.Exactly(t, frame[56:], reversed[56:])
|
||||||
|
|
||||||
toCompare := make([]byte, 48)
|
toCompare := make([]byte, 48)
|
||||||
for i := 0; i < 48; i++ {
|
for i := 0; i < 48; i++ {
|
||||||
toCompare[i] = frame[55-i]
|
toCompare[i] = frame[55-i]
|
||||||
}
|
}
|
||||||
assert.Equal(t, []byte((*reversed)[8:56]), toCompare)
|
assert.Equal(t, []byte(reversed[8:56]), toCompare)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFrameGenerateValid(t *testing.T) {
|
func TestFrameGenerateValid(t *testing.T) {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ type Obfuscated2 struct {
|
|||||||
// details: http://telegra.ph/telegram-blocks-wtf-05-26
|
// details: http://telegra.ph/telegram-blocks-wtf-05-26
|
||||||
//
|
//
|
||||||
// Beware, link above is in russian.
|
// Beware, link above is in russian.
|
||||||
func ParseObfuscated2ClientFrame(secret []byte, frame *Frame) (*Obfuscated2, *mtproto.ConnectionOpts, error) {
|
func ParseObfuscated2ClientFrame(secret []byte, frame Frame) (*Obfuscated2, *mtproto.ConnectionOpts, error) {
|
||||||
decHasher := sha256.New()
|
decHasher := sha256.New()
|
||||||
decHasher.Write(frame.Key()) // nolint: errcheck
|
decHasher.Write(frame.Key()) // nolint: errcheck
|
||||||
decHasher.Write(secret) // nolint: errcheck
|
decHasher.Write(secret) // nolint: errcheck
|
||||||
@@ -33,9 +33,8 @@ func ParseObfuscated2ClientFrame(secret []byte, frame *Frame) (*Obfuscated2, *mt
|
|||||||
encHasher.Write(secret) // nolint: errcheck
|
encHasher.Write(secret) // nolint: errcheck
|
||||||
encryptor := makeStreamCipher(encHasher.Sum(nil), invertedFrame.IV())
|
encryptor := makeStreamCipher(encHasher.Sum(nil), invertedFrame.IV())
|
||||||
|
|
||||||
decryptedFrame := MakeFrame()
|
decryptedFrame := make(Frame, FrameLen)
|
||||||
defer ReturnFrame(decryptedFrame)
|
decryptor.XORKeyStream(decryptedFrame, frame)
|
||||||
decryptor.XORKeyStream(*decryptedFrame, *frame)
|
|
||||||
connType, err := decryptedFrame.ConnectionType()
|
connType, err := decryptedFrame.ConnectionType()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, errors.Annotate(err, "Unknown protocol")
|
return nil, nil, errors.Annotate(err, "Unknown protocol")
|
||||||
@@ -56,18 +55,17 @@ func ParseObfuscated2ClientFrame(secret []byte, frame *Frame) (*Obfuscated2, *mt
|
|||||||
// MakeTelegramObfuscated2Frame creates new handshake frame to send to
|
// MakeTelegramObfuscated2Frame creates new handshake frame to send to
|
||||||
// Telegram.
|
// Telegram.
|
||||||
// https://blog.susanka.eu/how-telegram-obfuscates-its-mtproto-traffic/
|
// https://blog.susanka.eu/how-telegram-obfuscates-its-mtproto-traffic/
|
||||||
func MakeTelegramObfuscated2Frame(opts *mtproto.ConnectionOpts) (*Obfuscated2, *Frame) {
|
func MakeTelegramObfuscated2Frame(opts *mtproto.ConnectionOpts) (*Obfuscated2, Frame) {
|
||||||
frame := generateFrame(opts.ConnectionType)
|
frame := generateFrame(opts.ConnectionType)
|
||||||
|
|
||||||
encryptor := makeStreamCipher(frame.Key(), frame.IV())
|
encryptor := makeStreamCipher(frame.Key(), frame.IV())
|
||||||
decryptorFrame := frame.Invert()
|
decryptorFrame := frame.Invert()
|
||||||
decryptor := makeStreamCipher(decryptorFrame.Key(), decryptorFrame.IV())
|
decryptor := makeStreamCipher(decryptorFrame.Key(), decryptorFrame.IV())
|
||||||
|
|
||||||
copyFrame := MakeFrame()
|
copyFrame := make(Frame, FrameLen)
|
||||||
defer ReturnFrame(copyFrame)
|
copy(copyFrame[:frameOffsetIV], frame[:frameOffsetIV])
|
||||||
copy((*copyFrame)[:frameOffsetIV], (*frame)[:frameOffsetIV])
|
encryptor.XORKeyStream(frame, frame)
|
||||||
encryptor.XORKeyStream(*frame, *frame)
|
copy(frame[:frameOffsetIV], copyFrame[:frameOffsetIV])
|
||||||
copy((*frame)[:frameOffsetIV], (*copyFrame)[:frameOffsetIV])
|
|
||||||
|
|
||||||
obfs := &Obfuscated2{
|
obfs := &Obfuscated2{
|
||||||
Decryptor: decryptor,
|
Decryptor: decryptor,
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ func TestObfs2TelegramFrameDecrypt(t *testing.T) {
|
|||||||
decryptor := makeStreamCipher(frame.Key(), frame.IV())
|
decryptor := makeStreamCipher(frame.Key(), frame.IV())
|
||||||
|
|
||||||
decrypted := make(Frame, FrameLen)
|
decrypted := make(Frame, FrameLen)
|
||||||
decryptor.XORKeyStream(decrypted, *frame)
|
decryptor.XORKeyStream(decrypted, frame)
|
||||||
|
|
||||||
_, err := decrypted.ConnectionType()
|
_, err := decrypted.ConnectionType()
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
@@ -53,8 +53,8 @@ func TestObfs2Full(t *testing.T) {
|
|||||||
|
|
||||||
encryptor := makeStreamCipher(clientKey, clientFrame.IV())
|
encryptor := makeStreamCipher(clientKey, clientFrame.IV())
|
||||||
encrypted := make(Frame, FrameLen)
|
encrypted := make(Frame, FrameLen)
|
||||||
encryptor.XORKeyStream(encrypted, *clientFrame)
|
encryptor.XORKeyStream(encrypted, clientFrame)
|
||||||
copy(encrypted[:56], (*clientFrame)[:56])
|
copy(encrypted[:56], clientFrame[:56])
|
||||||
|
|
||||||
invertedClientFrame := clientFrame.Invert()
|
invertedClientFrame := clientFrame.Invert()
|
||||||
clientHasher = sha256.New()
|
clientHasher = sha256.New()
|
||||||
@@ -63,7 +63,7 @@ func TestObfs2Full(t *testing.T) {
|
|||||||
invertedClientKey := clientHasher.Sum(nil)
|
invertedClientKey := clientHasher.Sum(nil)
|
||||||
clientDecryptor := makeStreamCipher(invertedClientKey, invertedClientFrame.IV())
|
clientDecryptor := makeStreamCipher(invertedClientKey, invertedClientFrame.IV())
|
||||||
|
|
||||||
clientObfs, _, err := ParseObfuscated2ClientFrame(secret, &encrypted)
|
clientObfs, _, err := ParseObfuscated2ClientFrame(secret, encrypted)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
connOpts := &mtproto.ConnectionOpts{
|
connOpts := &mtproto.ConnectionOpts{
|
||||||
@@ -73,7 +73,7 @@ func TestObfs2Full(t *testing.T) {
|
|||||||
tgObfs, tgFrame := MakeTelegramObfuscated2Frame(connOpts)
|
tgObfs, tgFrame := MakeTelegramObfuscated2Frame(connOpts)
|
||||||
tgDecryptor := makeStreamCipher(tgFrame.Key(), tgFrame.IV())
|
tgDecryptor := makeStreamCipher(tgFrame.Key(), tgFrame.IV())
|
||||||
decrypted := make(Frame, FrameLen)
|
decrypted := make(Frame, FrameLen)
|
||||||
tgDecryptor.XORKeyStream(decrypted, *tgFrame)
|
tgDecryptor.XORKeyStream(decrypted, tgFrame)
|
||||||
_, err = decrypted.ConnectionType()
|
_, err = decrypted.ConnectionType()
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
|||||||
+1
-2
@@ -46,9 +46,8 @@ func (t *directTelegram) Dial(connOpts *mtproto.ConnectionOpts) (io.ReadWriteClo
|
|||||||
|
|
||||||
func (t *directTelegram) Init(connOpts *mtproto.ConnectionOpts, conn io.ReadWriteCloser) (io.ReadWriteCloser, error) {
|
func (t *directTelegram) Init(connOpts *mtproto.ConnectionOpts, conn io.ReadWriteCloser) (io.ReadWriteCloser, error) {
|
||||||
obfs2, frame := obfuscated2.MakeTelegramObfuscated2Frame(connOpts)
|
obfs2, frame := obfuscated2.MakeTelegramObfuscated2Frame(connOpts)
|
||||||
defer obfuscated2.ReturnFrame(frame)
|
|
||||||
|
|
||||||
if n, err := conn.Write(*frame); err != nil || n != len(*frame) {
|
if n, err := conn.Write(frame); err != nil || n != obfuscated2.FrameLen {
|
||||||
return nil, errors.Annotate(err, "Cannot write hadnshake frame")
|
return nil, errors.Annotate(err, "Cannot write hadnshake frame")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user