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.

crypt.go 2.3KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. package wrappers
  2. import (
  3. "bytes"
  4. "crypto/aes"
  5. "crypto/cipher"
  6. "crypto/md5"
  7. "crypto/sha1"
  8. "encoding/binary"
  9. "io"
  10. "net"
  11. "github.com/9seconds/mtg/mtproto/rpc"
  12. "github.com/9seconds/mtg/wrappers"
  13. )
  14. type CipherPurpose uint8
  15. const (
  16. CipherPurposeClient CipherPurpose = iota
  17. CipherPurposeServer
  18. )
  19. var emptyIP = [4]byte{0x00, 0x00, 0x00, 0x00}
  20. func NewMiddleProxyCipherRWC(conn io.ReadWriteCloser, req *rpc.RPCNonceRequest, resp *rpc.RPCNonceResponse, client *net.TCPAddr, remote *net.TCPAddr, secret []byte) io.ReadWriteCloser {
  21. encryptor := newCBCCipher(CipherPurposeClient, req, resp, client, remote, secret)
  22. decryptor := newCBCCipher(CipherPurposeServer, req, resp, client, remote, secret)
  23. return wrappers.NewBlockCipherRWC(conn, encryptor, decryptor)
  24. }
  25. func newCBCCipher(purpose CipherPurpose, req *rpc.RPCNonceRequest, resp *rpc.RPCNonceResponse, client *net.TCPAddr, remote *net.TCPAddr, secret []byte) cipher.BlockMode {
  26. message := bytes.Buffer{}
  27. message.Write(resp.Nonce[:])
  28. message.Write(req.Nonce[:])
  29. message.Write(req.CryptoTS[:])
  30. clientIPv4 := emptyIP[:]
  31. serverIPv4 := emptyIP[:]
  32. if client.IP.To4() != nil {
  33. clientIPv4 = reverseBytes(client.IP.To4())
  34. serverIPv4 = reverseBytes(remote.IP.To4())
  35. }
  36. message.Write(serverIPv4)
  37. var port [2]byte
  38. binary.LittleEndian.PutUint16(port[:], uint16(client.Port))
  39. message.Write(port[:])
  40. switch purpose {
  41. case CipherPurposeClient:
  42. message.WriteString("CLIENT")
  43. case CipherPurposeServer:
  44. message.WriteString("SERVER")
  45. default:
  46. panic("Unexpected cipher purpose")
  47. }
  48. message.Write(clientIPv4)
  49. binary.LittleEndian.PutUint16(port[:], uint16(remote.Port))
  50. message.Write(port[:])
  51. message.Write(secret)
  52. message.Write(resp.Nonce[:])
  53. if client.IP.To4() == nil {
  54. message.Write(client.IP.To16())
  55. message.Write(remote.IP.To16())
  56. }
  57. message.Write(req.Nonce[:])
  58. return makeCipher(message.Bytes())
  59. }
  60. func makeCipher(message []byte) cipher.BlockMode {
  61. md5sum := md5.Sum(message[1:])
  62. sha1sum := sha1.Sum(message)
  63. key := append(md5sum[12:], sha1sum[:]...)
  64. iv := md5.Sum(message[2:])
  65. block, err := aes.NewCipher(key)
  66. if err != nil {
  67. panic("Cannot create cipher from the given key")
  68. }
  69. return cipher.NewCBCEncrypter(block, iv[:])
  70. }
  71. func reverseBytes(data []byte) []byte {
  72. rv := make([]byte, len(data))
  73. for k, v := range data {
  74. rv[len(data)-1-k] = v
  75. }
  76. return rv
  77. }