Highly-opinionated (ex-bullshit-free) MTPROTO proxy for Telegram. If you use v1.0 or upgrade broke you proxy, please read the chapter Version 2
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. package fake
  2. import (
  3. "bytes"
  4. "crypto/hmac"
  5. "crypto/rand"
  6. "crypto/sha256"
  7. "encoding/binary"
  8. "io"
  9. rnd "math/rand/v2"
  10. "github.com/9seconds/mtg/v2/mtglib/internal/tls"
  11. "golang.org/x/crypto/curve25519"
  12. )
  13. // NoiseParams controls the size of the fake ApplicationData record
  14. // in ServerHello. If Mean is 0, the legacy random range (2500-4700)
  15. // is used.
  16. type NoiseParams struct {
  17. Mean int
  18. Jitter int
  19. }
  20. const (
  21. TypeHandshakeServer = 0x02
  22. ChangeCipherValue = 0x01
  23. EllipticCurveLen = 32
  24. )
  25. var serverHelloSuffix = []byte{
  26. 0x00, // no compression
  27. 0x00, 0x2e, // 46 bytes of data
  28. 0x00, 0x2b, // Extension - Supported Versions
  29. 0x00, 0x02, // 2 bytes are following
  30. 0x03, 0x04, // TLS 1.3
  31. 0x00, 0x33, // Extension - Key Share
  32. 0x00, 0x24, // 36 bytes
  33. 0x00, 0x1d, // x25519 curve
  34. 0x00, 0x20, // 32 bytes of key
  35. }
  36. func SendServerHello(w io.Writer, secret []byte, clientHello *ClientHello, noise NoiseParams) error {
  37. buf := &bytes.Buffer{}
  38. buf.Grow(tls.MaxRecordSize)
  39. generateServerHello(buf, clientHello)
  40. generateChangeCipherValue(buf)
  41. generateNoise(buf, noise)
  42. packet := buf.Bytes()
  43. digest := hmac.New(sha256.New, secret)
  44. digest.Write(clientHello.Random[:])
  45. digest.Write(packet)
  46. copy(packet[RandomOffset:], digest.Sum(nil))
  47. _, err := w.Write(packet)
  48. return err
  49. }
  50. func generateServerHello(buf *bytes.Buffer, hello *ClientHello) {
  51. payload := acquireBuffer()
  52. defer releaseBuffer(payload)
  53. generateServerHelloPayload(payload, hello)
  54. // 16 - type is 0x16 (handshake record)
  55. // 03 03 - legacy protocol version of "3,3" (TLS 1.2)
  56. // 00 7a - 0x7A (122) bytes of handshake message follows
  57. // 16 - type is 0x16 (handshake record)
  58. buf.WriteByte(tls.TypeHandshake)
  59. // 03 03 - legacy protocol version of "3,3" (TLS 1.2)
  60. buf.Write(tls.TLSVersion[:])
  61. // 00 7a - 0x7A (122) bytes of handshake message follows
  62. binary.Write(buf, binary.BigEndian, uint16(payload.Len())) //nolint: errcheck
  63. payload.WriteTo(buf) //nolint: errcheck
  64. }
  65. func generateServerHelloPayload(buf *bytes.Buffer, hello *ClientHello) {
  66. data := [4]byte{}
  67. payload := acquireBuffer()
  68. defer releaseBuffer(payload)
  69. generateServerHelloHandshakePayload(payload, hello)
  70. // 02 - handshake message type 0x02 (server hello)
  71. // 00 00 76 - 0x76 (118) bytes of server hello data follows
  72. buf.WriteByte(TypeHandshakeServer)
  73. // 00 00 76 - 0x76 (118) bytes of server hello data follows
  74. binary.BigEndian.PutUint32(data[:], uint32(payload.Len()))
  75. buf.Write(data[1:])
  76. payload.WriteTo(buf) //nolint: errcheck
  77. }
  78. func generateServerHelloHandshakePayload(buf *bytes.Buffer, hello *ClientHello) {
  79. // The unusual version number ("3,3" representing TLS 1.2) is due to
  80. // TLS 1.0 being a minor revision of the SSL 3.0 protocol. Therefore
  81. // TLS 1.0 is represented by "3,1", TLS 1.1 is "3,2", and so on.
  82. buf.Write(tls.TLSVersion[:])
  83. buf.Write(emptyRandom[:])
  84. // 20 - 0x20 (32) bytes of session ID follow
  85. // e0 e1 ... fe ff - session ID copied from Client Hello
  86. buf.WriteByte(byte(len(hello.SessionID)))
  87. buf.Write(hello.SessionID)
  88. binary.Write(buf, binary.BigEndian, hello.CipherSuite) //nolint: errcheck
  89. buf.Write(serverHelloSuffix)
  90. scalar := [EllipticCurveLen]byte{}
  91. if _, err := rand.Read(scalar[:]); err != nil {
  92. panic(err)
  93. }
  94. curve, _ := curve25519.X25519(scalar[:], curve25519.Basepoint)
  95. buf.Write(curve)
  96. }
  97. func generateChangeCipherValue(buf *bytes.Buffer) {
  98. buf.WriteByte(tls.TypeChangeCipherSpec)
  99. buf.Write(tls.TLSVersion[:])
  100. binary.Write(buf, binary.BigEndian, uint16(1)) //nolint: errcheck
  101. buf.WriteByte(ChangeCipherValue)
  102. }
  103. // generateNoise writes a single ApplicationData record mimicking the combined
  104. // size of a real TLS 1.3 encrypted server handshake (EncryptedExtensions +
  105. // Certificate chain + CertificateVerify + Finished).
  106. //
  107. // NOTE: Must be exactly ONE ApplicationData record — the Telegram client reads
  108. // ServerHello + CCS + 1 ApplicationData and computes HMAC over all three.
  109. // Multiple records would cause HMAC mismatch and connection failure.
  110. func generateNoise(buf *bytes.Buffer, noise NoiseParams) {
  111. var size int
  112. if noise.Mean > 0 && noise.Jitter > 0 {
  113. // Calibrated: use measured cert chain size ± jitter.
  114. size = noise.Mean - noise.Jitter + rnd.IntN(2*noise.Jitter)
  115. if size < 1000 {
  116. size = 1000
  117. }
  118. } else {
  119. // Legacy fallback: random in 2500-4700 range.
  120. size = 2500 + rnd.IntN(2200)
  121. }
  122. data := make([]byte, size)
  123. if _, err := rand.Read(data); err != nil {
  124. panic(err)
  125. }
  126. tls.WriteRecord(buf, data) //nolint: errcheck
  127. }