Files
mtproxy_checker/internal/mtproxy/header.go
T
Denozordec 4905c06b9b
Publish mtproxy_checker Docker image / test (push) Successful in 19s
Publish mtproxy_checker Docker image / build-and-push (push) Successful in 48s
init
2026-04-11 00:38:22 +07:00

104 lines
2.2 KiB
Go

package mtproxy
import (
"bytes"
"crypto/aes"
"crypto/cipher"
crand "crypto/rand"
"crypto/sha256"
"encoding/binary"
"fmt"
"io"
)
// ObfuscateTagRandomizedIntermediate matches Telethon RandomizedIntermediatePacketCodec.
var ObfuscateTagRandomizedIntermediate = []byte{0xdd, 0xdd, 0xdd, 0xdd}
// randSource is injectable for tests.
var randSource io.Reader = crand.Reader
// InitHeader returns the 64-byte first payload (MTProxyIO.init_header) and CTR streams.
func InitHeader(secret16 []byte, dcID int16) (header64 []byte, enc cipher.Stream, dec cipher.Stream, err error) {
if len(secret16) != 16 {
return nil, nil, nil, fmt.Errorf("mtproxy secret must be 16 bytes")
}
sec := secret16
keywords := [][]byte{
[]byte("PVrG"),
[]byte("GET "),
[]byte("POST"),
{0xee, 0xee, 0xee, 0xee},
}
var rnd [64]byte
for {
if _, err := io.ReadFull(randSource, rnd[:]); err != nil {
return nil, nil, nil, err
}
if rnd[0] == 0xef {
continue
}
bad := false
for _, k := range keywords {
if len(k) <= 4 && bytes.Equal(rnd[:len(k)], k) {
bad = true
break
}
}
if bad {
continue
}
if rnd[4] == 0 && rnd[5] == 0 && rnd[6] == 0 && rnd[7] == 0 {
continue
}
break
}
random := rnd[:]
rev := make([]byte, 48)
for i := 0; i < 48; i++ {
rev[i] = random[55-i]
}
encKey := sha256Sum(append(append([]byte{}, random[8:40]...), sec...))
encIV := random[40:56]
decKey := sha256Sum(append(append([]byte{}, rev[:32]...), sec...))
decIV := rev[32:48]
enc, err = newCTR(encKey, encIV)
if err != nil {
return nil, nil, nil, err
}
dec, err = newCTR(decKey, decIV)
if err != nil {
return nil, nil, nil, err
}
buf := make([]byte, 64)
copy(buf, random)
copy(buf[56:60], ObfuscateTagRandomizedIntermediate)
dcBytes := make([]byte, 2)
binary.LittleEndian.PutUint16(dcBytes, uint16(dcID))
copy(buf[60:62], dcBytes)
encChunk := make([]byte, 8)
copy(encChunk, buf[56:64])
enc.XORKeyStream(encChunk, encChunk)
copy(buf[56:64], encChunk)
return buf, enc, dec, nil
}
func sha256Sum(b []byte) []byte {
h := sha256.Sum256(b)
return h[:]
}
func newCTR(key, iv []byte) (cipher.Stream, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
return cipher.NewCTR(block, iv), nil
}