diff --git a/mtglib/internal/obfuscated2/client_handshake.go b/mtglib/internal/obfuscated2/client_handshake.go index 035086e..08bef5d 100644 --- a/mtglib/internal/obfuscated2/client_handshake.go +++ b/mtglib/internal/obfuscated2/client_handshake.go @@ -1,7 +1,6 @@ package obfuscated2 import ( - "crypto/aes" "crypto/cipher" "crypto/subtle" "encoding/hex" @@ -9,50 +8,21 @@ import ( "io" ) -// Connection Type secure. We support only fake tls. -var clientHandshakeConnectionType = []byte{0xdd, 0xdd, 0xdd, 0xdd} - func ClientHandshake(secret []byte, reader io.Reader) (int16, cipher.Stream, cipher.Stream, error) { - handshake := handshakeFrame{} + handshake := clientHandhakeFrame{} if _, err := io.ReadFull(reader, handshake.data[:]); err != nil { return 0, nil, nil, fmt.Errorf("cannot read frame: %w", err) } - decHasher := acquireSha256Hasher() - defer releaseSha256Hasher(decHasher) - - decHasher.Write(handshake.key()) // nolint: errcheck - decHasher.Write(secret) // nolint: errcheck - decryptor := makeAesCtr(decHasher.Sum(nil), handshake.iv()) - - encHasher := acquireSha256Hasher() - defer releaseSha256Hasher(encHasher) - - invertedHandshake := handshakeFrame{} - - for i, v := range handshake.data { - invertedHandshake.data[handshakeFrameLen-1-i] = v - } - - encHasher.Write(invertedHandshake.key()) // nolint: errcheck - encHasher.Write(secret) // nolint: errcheck - encryptor := makeAesCtr(encHasher.Sum(nil), invertedHandshake.iv()) + decryptor := handshake.decryptor(secret) + encryptor := handshake.encryptor(secret) decryptor.XORKeyStream(handshake.data[:], handshake.data[:]) - if val := handshake.connectionType(); subtle.ConstantTimeCompare(clientHandshakeConnectionType, val) != 1 { + if val := handshake.connectionType(); subtle.ConstantTimeCompare(handshakeConnectionType, val) != 1 { return 0, nil, nil, fmt.Errorf("unsupported connection type: %s", hex.EncodeToString(val)) } return handshake.dc(), encryptor, decryptor, nil } - -func makeAesCtr(key, iv []byte) cipher.Stream { - block, err := aes.NewCipher(key) - if err != nil { - panic(err) - } - - return cipher.NewCTR(block, iv) -} diff --git a/mtglib/internal/obfuscated2/client_handshake_frame.go b/mtglib/internal/obfuscated2/client_handshake_frame.go new file mode 100644 index 0000000..4d238f8 --- /dev/null +++ b/mtglib/internal/obfuscated2/client_handshake_frame.go @@ -0,0 +1,30 @@ +package obfuscated2 + +import "crypto/cipher" + +type clientHandhakeFrame struct { + handshakeFrame +} + +func (c *clientHandhakeFrame) decryptor(secret []byte) cipher.Stream { + hasher := acquireSha256Hasher() + defer releaseSha256Hasher(hasher) + + hasher.Write(c.key()) // nolint: errcheck + hasher.Write(secret) // nolint: errcheck + + return makeAesCtr(hasher.Sum(nil), c.iv()) +} + +func (c *clientHandhakeFrame) encryptor(secret []byte) cipher.Stream { + arr := clientHandhakeFrame{} + invertByteSlices(arr.data[:], c.data[:]) + + hasher := acquireSha256Hasher() + defer releaseSha256Hasher(hasher) + + hasher.Write(arr.key()) // nolint: errcheck + hasher.Write(secret) // nolint: errcheck + + return makeAesCtr(hasher.Sum(nil), arr.iv()) +} diff --git a/mtglib/internal/obfuscated2/handshake_frame.go b/mtglib/internal/obfuscated2/handshake_frame.go index 71a993c..919d7bb 100644 --- a/mtglib/internal/obfuscated2/handshake_frame.go +++ b/mtglib/internal/obfuscated2/handshake_frame.go @@ -18,6 +18,9 @@ const ( handshakeFrameOffsetEnd = handshakeFrameOffsetDC + handshakeFrameLenDC ) +// Connection-Type: Secure. We support only fake tls. +var handshakeConnectionType = []byte{0xdd, 0xdd, 0xdd, 0xdd} + // A structure of obfuscated2 handshake frame is following: // // [frameOffsetFirst:frameOffsetKey:frameOffsetIV:frameOffsetMagic:frameOffsetDC:frameOffsetEnd]. diff --git a/mtglib/internal/obfuscated2/utils.go b/mtglib/internal/obfuscated2/utils.go new file mode 100644 index 0000000..f32dde0 --- /dev/null +++ b/mtglib/internal/obfuscated2/utils.go @@ -0,0 +1,23 @@ +package obfuscated2 + +import ( + "crypto/aes" + "crypto/cipher" +) + +func makeAesCtr(key, iv []byte) cipher.Stream { + block, err := aes.NewCipher(key) + if err != nil { + panic(err) + } + + return cipher.NewCTR(block, iv) +} + +func invertByteSlices(dst, src []byte) { + lenDst := len(dst) - 1 + + for i, v := range src { + dst[lenDst-i] = v + } +}