init
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
package mtproxy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
crand "crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// ObfuscateTagRandomizedIntermediate matches Telethon RandomizedIntermediatePacketCodec.
|
||||
var ObfuscateTagRandomizedIntermediate = []byte{0xdd, 0xdd, 0xdd, 0xdd}
|
||||
|
||||
// randSource is injectable for tests.
|
||||
var randSource io.Reader = crand.Reader
|
||||
|
||||
// InitHeader returns the 64-byte first payload (MTProxyIO.init_header) and CTR streams.
|
||||
func InitHeader(secret16 []byte, dcID int16) (header64 []byte, enc cipher.Stream, dec cipher.Stream, err error) {
|
||||
if len(secret16) != 16 {
|
||||
return nil, nil, nil, fmt.Errorf("mtproxy secret must be 16 bytes")
|
||||
}
|
||||
sec := secret16
|
||||
|
||||
keywords := [][]byte{
|
||||
[]byte("PVrG"),
|
||||
[]byte("GET "),
|
||||
[]byte("POST"),
|
||||
{0xee, 0xee, 0xee, 0xee},
|
||||
}
|
||||
var rnd [64]byte
|
||||
for {
|
||||
if _, err := io.ReadFull(randSource, rnd[:]); err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
if rnd[0] == 0xef {
|
||||
continue
|
||||
}
|
||||
bad := false
|
||||
for _, k := range keywords {
|
||||
if len(k) <= 4 && bytes.Equal(rnd[:len(k)], k) {
|
||||
bad = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if bad {
|
||||
continue
|
||||
}
|
||||
if rnd[4] == 0 && rnd[5] == 0 && rnd[6] == 0 && rnd[7] == 0 {
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
random := rnd[:]
|
||||
rev := make([]byte, 48)
|
||||
for i := 0; i < 48; i++ {
|
||||
rev[i] = random[55-i]
|
||||
}
|
||||
|
||||
encKey := sha256Sum(append(append([]byte{}, random[8:40]...), sec...))
|
||||
encIV := random[40:56]
|
||||
decKey := sha256Sum(append(append([]byte{}, rev[:32]...), sec...))
|
||||
decIV := rev[32:48]
|
||||
|
||||
enc, err = newCTR(encKey, encIV)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
dec, err = newCTR(decKey, decIV)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
buf := make([]byte, 64)
|
||||
copy(buf, random)
|
||||
copy(buf[56:60], ObfuscateTagRandomizedIntermediate)
|
||||
dcBytes := make([]byte, 2)
|
||||
binary.LittleEndian.PutUint16(dcBytes, uint16(dcID))
|
||||
copy(buf[60:62], dcBytes)
|
||||
|
||||
encChunk := make([]byte, 8)
|
||||
copy(encChunk, buf[56:64])
|
||||
enc.XORKeyStream(encChunk, encChunk)
|
||||
copy(buf[56:64], encChunk)
|
||||
|
||||
return buf, enc, dec, nil
|
||||
}
|
||||
|
||||
func sha256Sum(b []byte) []byte {
|
||||
h := sha256.Sum256(b)
|
||||
return h[:]
|
||||
}
|
||||
|
||||
func newCTR(key, iv []byte) (cipher.Stream, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cipher.NewCTR(block, iv), nil
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package mtproxy
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestInitHeader_Length(t *testing.T) {
|
||||
key := make([]byte, 16)
|
||||
for i := range key {
|
||||
key[i] = byte(i + 1)
|
||||
}
|
||||
hdr, enc, dec, err := InitHeader(key, 2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(hdr) != 64 {
|
||||
t.Fatalf("header len %d", len(hdr))
|
||||
}
|
||||
_ = enc
|
||||
_ = dec
|
||||
}
|
||||
Reference in New Issue
Block a user