From 3a44bcb8545cda70bb1946a5774c4801c7f201ca Mon Sep 17 00:00:00 2001 From: 9seconds Date: Thu, 18 Mar 2021 15:01:22 +0300 Subject: [PATCH] Introduce pools to obfuscated2 --- .../internal/obfuscated2/client_handshake.go | 27 ++++++++--- mtglib/internal/obfuscated2/frame.go | 48 ++++--------------- mtglib/internal/obfuscated2/pools.go | 25 ++++++++-- mtglib/proxy.go | 7 +-- 4 files changed, 51 insertions(+), 56 deletions(-) diff --git a/mtglib/internal/obfuscated2/client_handshake.go b/mtglib/internal/obfuscated2/client_handshake.go index 275afb0..f5e692f 100644 --- a/mtglib/internal/obfuscated2/client_handshake.go +++ b/mtglib/internal/obfuscated2/client_handshake.go @@ -5,12 +5,20 @@ import ( "crypto/subtle" "encoding/hex" "fmt" + "io" ) // Connection Type secure. We support only fake tls. var clientHandshakeMagic = []byte{0xdd, 0xdd, 0xdd, 0xdd} -func ClientHandshake(secret []byte, handshakeFrame *HandhakeFrame) (int16, cipher.Stream, cipher.Stream, error) { +func ClientHandshake(secret []byte, reader io.Reader) (int16, cipher.Stream, cipher.Stream, error) { + handshakeFrame := acquireHandshakeFrame() + defer releaseHandshakeFrame(handshakeFrame) + + if _, err := io.ReadFull(reader, handshakeFrame.data[:]); err != nil { + return 0, nil, nil, fmt.Errorf("cannot read frame: %w", err) + } + decHasher := acquireSha256Hasher() defer releaseSha256Hasher(decHasher) @@ -21,17 +29,22 @@ func ClientHandshake(secret []byte, handshakeFrame *HandhakeFrame) (int16, ciphe encHasher := acquireSha256Hasher() defer releaseSha256Hasher(encHasher) - invertedFrame := handshakeFrame.invert() + invertedFrame := acquireHandshakeFrame() + defer releaseHandshakeFrame(invertedFrame) + + for i, v := range handshakeFrame.data { + invertedFrame.data[handshakeFrameLen-1-i] = v + } + encHasher.Write(invertedFrame.key()) // nolint: errcheck - encHasher.Write(secret) // nolint: errcheck + encHasher.Write(secret) // nolint: errcheck encryptor := makeAesCtr(encHasher.Sum(nil), invertedFrame.iv()) - decryptedFrame := HandhakeFrame{} - decryptor.XORKeyStream(decryptedFrame.data[:], handshakeFrame.data[:]) + decryptor.XORKeyStream(handshakeFrame.data[:], handshakeFrame.data[:]) - if magic := decryptedFrame.magic(); subtle.ConstantTimeCompare(clientHandshakeMagic, magic) != 1 { + if magic := handshakeFrame.magic(); subtle.ConstantTimeCompare(clientHandshakeMagic, magic) != 1 { return 0, nil, nil, fmt.Errorf("unsupported connection type: %s", hex.EncodeToString(magic)) } - return decryptedFrame.dc(), encryptor, decryptor, nil + return handshakeFrame.dc(), encryptor, decryptor, nil } diff --git a/mtglib/internal/obfuscated2/frame.go b/mtglib/internal/obfuscated2/frame.go index 0526972..f84a07d 100644 --- a/mtglib/internal/obfuscated2/frame.go +++ b/mtglib/internal/obfuscated2/frame.go @@ -1,10 +1,6 @@ package obfuscated2 -import ( - "encoding/binary" - "fmt" - "io" -) +import "encoding/binary" const ( handshakeFrameLen = 64 @@ -32,48 +28,24 @@ const ( // - 4 bytes of 'magic' - this has some settings like a connection type // - 2 bytes of 'DC'. DC is little endian int16 // - 2 bytes of noise -type HandhakeFrame struct { +type handshakeFrame struct { data [handshakeFrameLen]byte } -func (f *HandhakeFrame) Fingerprint() []byte { - return f.data[handshakeFrameOffsetStart:handshakeFrameOffsetEnd] -} - -func (f *HandhakeFrame) dc() int16 { - data := f.data[handshakeFrameOffsetDC:handshakeFrameOffsetEnd] +func (h *handshakeFrame) dc() int16 { + data := h.data[handshakeFrameOffsetDC:handshakeFrameOffsetEnd] return int16(binary.LittleEndian.Uint16(data)) } -func (f *HandhakeFrame) key() []byte { - return f.data[handshakeFrameLenKey:handshakeFrameOffsetIV] +func (h *handshakeFrame) key() []byte { + return h.data[handshakeFrameLenKey:handshakeFrameOffsetIV] } -func (f *HandhakeFrame) iv() []byte { - return f.data[handshakeFrameOffsetIV:handshakeFrameOffsetMagic] +func (h *handshakeFrame) iv() []byte { + return h.data[handshakeFrameOffsetIV:handshakeFrameOffsetMagic] } -func (f *HandhakeFrame) magic() []byte { - return f.data[handshakeFrameOffsetMagic:handshakeFrameOffsetDC] -} - -func (f *HandhakeFrame) invert() *HandhakeFrame { - newFrame := &HandhakeFrame{} - - for i, v := range f.data { - newFrame.data[handshakeFrameLen-1-i] = v - } - - return newFrame -} - -func ReadHandshakeFrame(reader io.Reader) (*HandhakeFrame, error) { - frame := &HandhakeFrame{} - - if _, err := io.ReadFull(reader, frame.data[:]); err != nil { - return nil, fmt.Errorf("cannot read frame data: %w", err) - } - - return frame, nil +func (h *handshakeFrame) magic() []byte { + return h.data[handshakeFrameOffsetMagic:handshakeFrameOffsetDC] } diff --git a/mtglib/internal/obfuscated2/pools.go b/mtglib/internal/obfuscated2/pools.go index ce3204f..222514e 100644 --- a/mtglib/internal/obfuscated2/pools.go +++ b/mtglib/internal/obfuscated2/pools.go @@ -6,11 +6,18 @@ import ( "sync" ) -var sha256HasherPool = sync.Pool{ - New: func() interface{} { - return sha256.New() - }, -} +var ( + sha256HasherPool = sync.Pool{ + New: func() interface{} { + return sha256.New() + }, + } + handshakeFramePool = sync.Pool{ + New: func() interface{} { + return &handshakeFrame{} + }, + } +) func acquireSha256Hasher() hash.Hash { return sha256HasherPool.Get().(hash.Hash) @@ -20,3 +27,11 @@ func releaseSha256Hasher(h hash.Hash) { h.Reset() sha256HasherPool.Put(h) } + +func acquireHandshakeFrame() *handshakeFrame { + return handshakeFramePool.Get().(*handshakeFrame) +} + +func releaseHandshakeFrame(h *handshakeFrame) { + handshakeFramePool.Put(h) +} diff --git a/mtglib/proxy.go b/mtglib/proxy.go index 3c3bad2..1dd76cd 100644 --- a/mtglib/proxy.go +++ b/mtglib/proxy.go @@ -95,12 +95,7 @@ func (p *Proxy) Shutdown() { } func (p *Proxy) doObfuscated2Handshake(ctx *streamContext) error { - handshakeFrame, err := obfuscated2.ReadHandshakeFrame(ctx.clientConn) - if err != nil { - return fmt.Errorf("cannot read handshake frame: %w", err) - } - - dc, encryptor, decryptor, err := obfuscated2.ClientHandshake(p.secret.Key[:], handshakeFrame) + dc, encryptor, decryptor, err := obfuscated2.ClientHandshake(p.secret.Key[:], ctx.clientConn) if err != nil { return fmt.Errorf("cannot process client handshake: %w", err) }