Files
mautrix-telegram/pkg/gotd/mtproxy/faketls/client_hello.go
T
2025-06-27 20:03:37 -07:00

125 lines
3.0 KiB
Go

package faketls
import (
"crypto/hmac"
"crypto/sha256"
"encoding/binary"
"io"
"github.com/go-faster/errors"
"go.mau.fi/mautrix-telegram/pkg/gotd/bin"
"go.mau.fi/mautrix-telegram/pkg/gotd/clock"
)
const clientHelloLength = 517
func createClientHello(b *bin.Buffer, sessionID [32]byte, domain string, key [32]byte) (randomOffset int) {
S := func(s string) {
b.Buf = append(b.Buf, s...)
}
Z := func(n int) {
randomOffset = len(b.Buf)
b.Expand(n)
}
G := func(_ int) {
b.Expand(0)
}
R := func() {
b.Buf = append(b.Buf, sessionID[:]...)
}
D := func() {
b.Buf = append(b.Buf, domain...)
}
K := func() {
b.Buf = append(b.Buf, key[:]...)
}
var stack []int
Open := func() {
stack = append(stack, b.Len())
b.Expand(2)
}
Close := func() {
lastIdx := len(stack) - 1
s := stack[lastIdx]
stack = stack[:lastIdx]
length := b.Len() - (s + 2)
binary.BigEndian.PutUint16(b.Buf[s:], uint16(length))
}
S("\x16\x03\x01\x02\x00\x01\x00\x01\xfc\x03\x03")
Z(32)
S("\x20")
R()
S("\x00\x20")
G(0)
S("\x13\x01\x13\x02\x13\x03\xc0\x2b\xc0\x2f\xc0\x2c\xc0\x30\xcc\xa9" +
"\xcc\xa8\xc0\x13\xc0\x14\x00\x9c\x00\x9d\x00\x2f\x00\x35\x01\x00" +
"\x01\x93")
G(2)
S("\x00\x00\x00\x00")
Open()
Open()
S("\x00")
Open()
D()
Close()
Close()
Close()
S("\x00\x17\x00\x00\xff\x01\x00\x01\x00\x00\x0a\x00\x0a\x00\x08")
G(4)
S("\x00\x1d\x00\x17\x00\x18\x00\x0b\x00\x02\x01\x00\x00\x23\x00\x00" +
"\x00\x10\x00\x0e\x00\x0c\x02\x68\x32\x08\x68\x74\x74\x70\x2f\x31" +
"\x2e\x31\x00\x05\x00\x05\x01\x00\x00\x00\x00\x00\x0d\x00\x12\x00" +
"\x10\x04\x03\x08\x04\x04\x01\x05\x03\x08\x05\x05\x01\x08\x06\x06" +
"\x01\x00\x12\x00\x00\x00\x33\x00\x2b\x00\x29")
G(4)
S("\x00\x01\x00\x00\x1d\x00\x20")
K()
S("\x00\x2d\x00\x02\x01\x01\x00\x2b\x00\x0b\x0a")
G(6)
S("\x03\x04\x03\x03\x03\x02\x03\x01\x00\x1b\x00\x03\x02\x00\x02")
G(3)
S("\x00\x01\x00\x00\x15")
if pad := clientHelloLength - b.Len(); pad > 0 {
b.Expand(pad)
}
return randomOffset
}
// writeClientHello writes faketls ClientHello.
//
// See https://tools.ietf.org/html/rfc5246#section-7.4.1.1.
func writeClientHello(
w io.Writer,
now clock.Clock,
sessionID [32]byte,
domain string,
secret []byte,
) (r [32]byte, err error) {
b := &bin.Buffer{
Buf: make([]byte, 0, 576),
}
randomOffset := createClientHello(b, sessionID, domain, [32]byte{})
// https://github.com/tdlib/td/blob/27d3fdd09d90f6b77ecbcce50b1e86dc4b3dd366/td/mtproto/TlsInit.cpp#L380-L384
mac := hmac.New(sha256.New, secret)
if _, err := mac.Write(b.Buf); err != nil {
return [32]byte{}, errors.Wrap(err, "hmac write")
}
s := mac.Sum(nil)
copy(b.Buf[randomOffset:randomOffset+32], s)
// Overwrite last 4 bytes using final := original ^ timestamp.
old := binary.LittleEndian.Uint32(b.Buf[randomOffset+28 : randomOffset+32])
old ^= uint32(now.Now().Unix())
binary.LittleEndian.PutUint32(b.Buf[randomOffset+28:randomOffset+32], old)
// Copy ClientRandom for later use.
copy(r[:], b.Buf[randomOffset:randomOffset+32])
_, err = w.Write(b.Buf)
return r, err
}