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.

client_hello.go 1.7KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. package faketls
  2. import (
  3. "crypto/hmac"
  4. "crypto/sha256"
  5. "encoding/binary"
  6. "fmt"
  7. "time"
  8. "github.com/9seconds/mtg/v2/mtglib/internal/faketls/record"
  9. )
  10. type ClientHello struct {
  11. Time time.Time
  12. Random [RandomLen]byte
  13. SessionID []byte
  14. CipherSuite uint16
  15. }
  16. func ParseClientHello(secret, handshake []byte) (ClientHello, error) {
  17. hello := ClientHello{}
  18. if len(handshake) < ClientHelloMinLen {
  19. return hello, fmt.Errorf("lengh of handshake is too small: %d", len(handshake))
  20. }
  21. if handshake[0] != HandshakeTypeClient {
  22. return hello, fmt.Errorf("unknown handshake type %#x", handshake[0])
  23. }
  24. copy(hello.Random[:], handshake[ClientHelloRandomOffset:])
  25. for i := ClientHelloRandomOffset; i < ClientHelloRandomOffset+RandomLen; i++ {
  26. handshake[i] = 0
  27. }
  28. rec := record.AcquireRecord()
  29. defer record.ReleaseRecord(rec)
  30. rec.Type = record.TypeHandshake
  31. rec.Version = record.Version10
  32. rec.Payload.Write(handshake)
  33. // mac is calculated for the whole record, not only
  34. // for the payload part
  35. mac := hmac.New(sha256.New, secret)
  36. rec.Dump(mac) // nolint: errcheck
  37. computedRandom := mac.Sum(nil)
  38. for i := 0; i < RandomLen; i++ {
  39. computedRandom[i] ^= hello.Random[i]
  40. }
  41. for i := 0; i < RandomLen-4; i++ {
  42. if computedRandom[i] != 0 {
  43. return hello, ErrBadDigest
  44. }
  45. }
  46. timestamp := int64(binary.LittleEndian.Uint32(computedRandom[RandomLen-4:]))
  47. hello.Time = time.Unix(timestamp, 0)
  48. hello.SessionID = make([]byte, handshake[ClientHelloSessionIDOffset])
  49. copy(hello.SessionID, handshake[ClientHelloSessionIDOffset+1:])
  50. cipherSuiteOffset := ClientHelloSessionIDOffset + len(hello.SessionID) + 3 // nolint: gomnd
  51. hello.CipherSuite = binary.BigEndian.Uint16(handshake[cipherSuiteOffset : cipherSuiteOffset+2])
  52. return hello, nil
  53. }