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.

obfuscated2.go 2.3KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. package obfuscated2
  2. import (
  3. "crypto/aes"
  4. "crypto/cipher"
  5. "crypto/sha256"
  6. "github.com/juju/errors"
  7. "github.com/9seconds/mtg/mtproto"
  8. )
  9. // Obfuscated2 contains AES CTR encryption and decryption streams
  10. // for telegram connection.
  11. type Obfuscated2 struct {
  12. Decryptor cipher.Stream
  13. Encryptor cipher.Stream
  14. }
  15. // ParseObfuscated2ClientFrame parses client frame. Please check this link for
  16. // details: http://telegra.ph/telegram-blocks-wtf-05-26
  17. //
  18. // Beware, link above is in russian.
  19. func ParseObfuscated2ClientFrame(secret []byte, frame *Frame) (*Obfuscated2, *mtproto.ConnectionOpts, error) {
  20. decHasher := sha256.New()
  21. decHasher.Write(frame.Key()) // nolint: errcheck
  22. decHasher.Write(secret) // nolint: errcheck
  23. decryptor := makeStreamCipher(decHasher.Sum(nil), frame.IV())
  24. invertedFrame := frame.Invert()
  25. encHasher := sha256.New()
  26. encHasher.Write(invertedFrame.Key()) // nolint: errcheck
  27. encHasher.Write(secret) // nolint: errcheck
  28. encryptor := makeStreamCipher(encHasher.Sum(nil), invertedFrame.IV())
  29. decryptedFrame := MakeFrame()
  30. defer ReturnFrame(decryptedFrame)
  31. decryptor.XORKeyStream(*decryptedFrame, *frame)
  32. connType, err := decryptedFrame.ConnectionType()
  33. if err != nil {
  34. return nil, nil, errors.Annotate(err, "Unknown protocol")
  35. }
  36. obfs := &Obfuscated2{
  37. Decryptor: decryptor,
  38. Encryptor: encryptor,
  39. }
  40. connOpts := &mtproto.ConnectionOpts{
  41. DC: decryptedFrame.DC(),
  42. ConnectionType: connType,
  43. }
  44. return obfs, connOpts, nil
  45. }
  46. // MakeTelegramObfuscated2Frame creates new handshake frame to send to
  47. // Telegram.
  48. // https://blog.susanka.eu/how-telegram-obfuscates-its-mtproto-traffic/
  49. func MakeTelegramObfuscated2Frame(opts *mtproto.ConnectionOpts) (*Obfuscated2, *Frame) {
  50. frame := generateFrame(opts.ConnectionType)
  51. encryptor := makeStreamCipher(frame.Key(), frame.IV())
  52. decryptorFrame := frame.Invert()
  53. decryptor := makeStreamCipher(decryptorFrame.Key(), decryptorFrame.IV())
  54. copyFrame := MakeFrame()
  55. defer ReturnFrame(copyFrame)
  56. copy((*copyFrame)[:frameOffsetIV], (*frame)[:frameOffsetIV])
  57. encryptor.XORKeyStream(*frame, *frame)
  58. copy((*frame)[:frameOffsetIV], (*copyFrame)[:frameOffsetIV])
  59. obfs := &Obfuscated2{
  60. Decryptor: decryptor,
  61. Encryptor: encryptor,
  62. }
  63. return obfs, frame
  64. }
  65. func makeStreamCipher(key, iv []byte) cipher.Stream {
  66. block, _ := aes.NewCipher(key)
  67. return cipher.NewCTR(block, iv)
  68. }