mirror of
https://github.com/nadoo/glider.git
synced 2025-02-24 17:55:41 +08:00
280 lines
7.8 KiB
Go
280 lines
7.8 KiB
Go
![]() |
package obfs
|
||
|
|
||
|
import (
|
||
|
"crypto/hmac"
|
||
|
"encoding/binary"
|
||
|
"fmt"
|
||
|
"math/rand"
|
||
|
"strings"
|
||
|
"time"
|
||
|
|
||
|
"github.com/sun8911879/shadowsocksR/ssr"
|
||
|
"github.com/sun8911879/shadowsocksR/tools"
|
||
|
)
|
||
|
|
||
|
func init() {
|
||
|
register("tls1.2_ticket_auth", newTLS12TicketAuth)
|
||
|
}
|
||
|
|
||
|
type tlsAuthData struct {
|
||
|
localClientID [32]byte
|
||
|
}
|
||
|
|
||
|
// tls12TicketAuth tls1.2_ticket_auth obfs encapsulate
|
||
|
type tls12TicketAuth struct {
|
||
|
ssr.ServerInfoForObfs
|
||
|
data *tlsAuthData
|
||
|
sendID int
|
||
|
handshakeStatus int
|
||
|
sendBuffer []byte
|
||
|
}
|
||
|
|
||
|
// newTLS12TicketAuth create a tlv1.2_ticket_auth object
|
||
|
func newTLS12TicketAuth() IObfs {
|
||
|
return &tls12TicketAuth{}
|
||
|
}
|
||
|
|
||
|
func (t *tls12TicketAuth) SetServerInfo(s *ssr.ServerInfoForObfs) {
|
||
|
t.ServerInfoForObfs = *s
|
||
|
}
|
||
|
|
||
|
func (t *tls12TicketAuth) GetServerInfo() (s *ssr.ServerInfoForObfs) {
|
||
|
return &t.ServerInfoForObfs
|
||
|
}
|
||
|
|
||
|
func (t *tls12TicketAuth) SetData(data interface{}) {
|
||
|
if auth, ok := data.(*tlsAuthData); ok {
|
||
|
t.data = auth
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (t *tls12TicketAuth) GetData() interface{} {
|
||
|
if t.data == nil {
|
||
|
t.data = &tlsAuthData{}
|
||
|
b := make([]byte, 32)
|
||
|
rand.Read(b)
|
||
|
copy(t.data.localClientID[:], b)
|
||
|
}
|
||
|
return t.data
|
||
|
}
|
||
|
|
||
|
func (t *tls12TicketAuth) getHost() string {
|
||
|
host := t.Host
|
||
|
if len(t.Param) > 0 {
|
||
|
hosts := strings.Split(t.Param, ",")
|
||
|
if len(hosts) > 0 {
|
||
|
host = hosts[rand.Intn(len(hosts))]
|
||
|
host = strings.TrimSpace(host)
|
||
|
}
|
||
|
}
|
||
|
if len(host) > 0 && host[len(host)-1] >= byte('0') && host[len(host)-1] <= byte('9') && len(t.Param) == 0 {
|
||
|
host = ""
|
||
|
}
|
||
|
return host
|
||
|
}
|
||
|
|
||
|
func (t *tls12TicketAuth) Encode(data []byte) (encodedData []byte, err error) {
|
||
|
if t.handshakeStatus == -1 {
|
||
|
return data, nil
|
||
|
}
|
||
|
dataLength := len(data)
|
||
|
|
||
|
if t.handshakeStatus == 8 {
|
||
|
encodedData = make([]byte, dataLength+4096)
|
||
|
start := 0
|
||
|
outLength := 0
|
||
|
|
||
|
for t.sendID <= 4 && dataLength-start > 256 {
|
||
|
length := rand.Intn(512) + 64
|
||
|
if length > dataLength-start {
|
||
|
length = dataLength - start
|
||
|
}
|
||
|
copy(encodedData[outLength:], []byte{0x17, 0x3, 0x3})
|
||
|
binary.BigEndian.PutUint16(encodedData[outLength+3:], uint16(length&0xFFFF))
|
||
|
copy(encodedData[outLength+5:], data[start:start+length])
|
||
|
start += length
|
||
|
outLength += length + 5
|
||
|
t.sendID++
|
||
|
}
|
||
|
for dataLength-start > 2048 {
|
||
|
length := rand.Intn(3990) + 100
|
||
|
if length > dataLength-start {
|
||
|
length = dataLength - start
|
||
|
}
|
||
|
copy(encodedData[outLength:], []byte{0x17, 0x3, 0x3})
|
||
|
binary.BigEndian.PutUint16(encodedData[outLength+3:], uint16(length&0xFFFF))
|
||
|
copy(encodedData[outLength+5:], data[start:start+length])
|
||
|
start += length
|
||
|
outLength += length + 5
|
||
|
t.sendID++
|
||
|
}
|
||
|
if dataLength-start > 0 {
|
||
|
length := dataLength - start
|
||
|
copy(encodedData[outLength:], []byte{0x17, 0x3, 0x3})
|
||
|
binary.BigEndian.PutUint16(encodedData[outLength+3:], uint16(length&0xFFFF))
|
||
|
copy(encodedData[outLength+5:], data[start:start+length])
|
||
|
// not necessary to update variable *start* any more
|
||
|
outLength += length + 5
|
||
|
t.sendID++
|
||
|
}
|
||
|
encodedData = encodedData[:outLength]
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if t.handshakeStatus == 1 {
|
||
|
//outLength := 0
|
||
|
if dataLength > 0 {
|
||
|
b := make([]byte, len(t.sendBuffer)+dataLength+5)
|
||
|
copy(b, t.sendBuffer)
|
||
|
copy(b[len(t.sendBuffer):], []byte{0x17, 0x3, 0x3})
|
||
|
binary.BigEndian.PutUint16(b[len(t.sendBuffer)+3:], uint16(dataLength&0xFFFF))
|
||
|
copy(b[len(t.sendBuffer)+5:], data)
|
||
|
t.sendBuffer = b
|
||
|
return []byte{}, nil
|
||
|
}
|
||
|
|
||
|
hmacData := make([]byte, 43)
|
||
|
rnd := make([]byte, 22)
|
||
|
rand.Read(rnd)
|
||
|
|
||
|
handshakeFinish := []byte("\x14\x03\x03\x00\x01\x01\x16\x03\x03\x00\x20")
|
||
|
copy(hmacData, handshakeFinish)
|
||
|
copy(hmacData[len(handshakeFinish):], rnd)
|
||
|
|
||
|
h := t.hmacSHA1(hmacData[:33])
|
||
|
copy(hmacData[33:], h)
|
||
|
|
||
|
encodedData = make([]byte, len(hmacData)+len(t.sendBuffer))
|
||
|
copy(encodedData, hmacData)
|
||
|
copy(encodedData[len(hmacData):], t.sendBuffer)
|
||
|
t.sendBuffer = nil
|
||
|
t.handshakeStatus = 8
|
||
|
|
||
|
return
|
||
|
}
|
||
|
|
||
|
rnd := t.packAuthData()
|
||
|
|
||
|
tlsData0 := []byte("\x00\x1c\xc0\x2b\xc0\x2f\xcc\xa9\xcc\xa8\xcc\x14\xcc\x13\xc0\x0a\xc0\x14\xc0\x09\xc0\x13\x00\x9c\x00\x35\x00\x2f\x00\x0a\x01\x00")
|
||
|
tlsData1 := []byte("\xff\x01\x00\x01\x00")
|
||
|
tlsData2 := []byte("\x00\x17\x00\x00\x00\x23\x00\xd0")
|
||
|
tlsData3 := []byte("\x00\x0d\x00\x16\x00\x14\x06\x01\x06\x03\x05\x01\x05\x03\x04\x01\x04\x03\x03\x01\x03\x03\x02\x01\x02\x03\x00\x05\x00\x05\x01\x00\x00\x00\x00\x00\x12\x00\x00\x75\x50\x00\x00\x00\x0b\x00\x02\x01\x00\x00\x0a\x00\x06\x00\x04\x00\x17\x00\x18" +
|
||
|
"\x00\x15\x00\x66\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
|
||
|
|
||
|
var sslBuf []byte
|
||
|
sslBuf = append(sslBuf, rnd...)
|
||
|
sslBuf = append(sslBuf, byte(32))
|
||
|
sslBuf = append(sslBuf, t.data.localClientID[:]...)
|
||
|
sslBuf = append(sslBuf, tlsData0...)
|
||
|
|
||
|
var extBuf []byte
|
||
|
extBuf = append(extBuf, tlsData1...)
|
||
|
|
||
|
host := t.getHost()
|
||
|
|
||
|
extBuf = append(extBuf, t.sni(host)...)
|
||
|
extBuf = append(extBuf, tlsData2...)
|
||
|
ticket := make([]byte, 208)
|
||
|
rand.Read(ticket)
|
||
|
extBuf = append(extBuf, ticket...)
|
||
|
extBuf = append(extBuf, tlsData3...)
|
||
|
extBuf = append([]byte{byte(len(extBuf) / 256), byte(len(extBuf) % 256)}, extBuf...)
|
||
|
|
||
|
sslBuf = append(sslBuf, extBuf...)
|
||
|
// client version
|
||
|
sslBuf = append([]byte{3, 3}, sslBuf...)
|
||
|
// length
|
||
|
sslBuf = append([]byte{1, 0, byte(len(sslBuf) / 256), byte(len(sslBuf) % 256)}, sslBuf...)
|
||
|
// length
|
||
|
sslBuf = append([]byte{byte(len(sslBuf) / 256), byte(len(sslBuf) % 256)}, sslBuf...)
|
||
|
// version
|
||
|
sslBuf = append([]byte{0x16, 3, 1}, sslBuf...)
|
||
|
|
||
|
encodedData = sslBuf
|
||
|
|
||
|
d := make([]byte, dataLength+5)
|
||
|
copy(d[0:], []byte{0x17, 0x3, 0x3})
|
||
|
binary.BigEndian.PutUint16(d[3:], uint16(dataLength&0xFFFF))
|
||
|
copy(d[5:], data)
|
||
|
b := make([]byte, len(t.sendBuffer)+len(d))
|
||
|
copy(b, t.sendBuffer)
|
||
|
copy(b[len(t.sendBuffer):], d)
|
||
|
t.sendBuffer = b
|
||
|
|
||
|
t.handshakeStatus = 1
|
||
|
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (t *tls12TicketAuth) Decode(data []byte) ([]byte, uint64, error) {
|
||
|
if t.handshakeStatus == -1 {
|
||
|
return data, 0, nil
|
||
|
}
|
||
|
dataLength := len(data)
|
||
|
|
||
|
if t.handshakeStatus == 8 {
|
||
|
if dataLength < 5 {
|
||
|
return nil, 5, fmt.Errorf("data need minimum length: 5 ,data only length: %d", dataLength)
|
||
|
}
|
||
|
if data[0] != 0x17 {
|
||
|
return nil, 0, ssr.ErrTLS12TicketAuthIncorrectMagicNumber
|
||
|
}
|
||
|
size := int(binary.BigEndian.Uint16(data[3:5]))
|
||
|
if size+5 > dataLength {
|
||
|
return nil, uint64(size + 5), fmt.Errorf("unexpected data length: %d ,data only length: %d", size+5, dataLength)
|
||
|
}
|
||
|
if dataLength == size+5 {
|
||
|
return data[5:], 0, nil
|
||
|
}
|
||
|
return data[5 : 5+size], uint64(size + 5), nil
|
||
|
}
|
||
|
|
||
|
if dataLength < 11+32+1+32 {
|
||
|
return nil, 0, ssr.ErrTLS12TicketAuthTooShortData
|
||
|
}
|
||
|
|
||
|
hash := t.hmacSHA1(data[11 : 11+22])
|
||
|
|
||
|
if !hmac.Equal(data[33:33+ssr.ObfsHMACSHA1Len], hash) {
|
||
|
return nil, 0, ssr.ErrTLS12TicketAuthHMACError
|
||
|
}
|
||
|
return nil, 1, nil
|
||
|
}
|
||
|
|
||
|
func (t *tls12TicketAuth) packAuthData() (outData []byte) {
|
||
|
outSize := 32
|
||
|
outData = make([]byte, outSize)
|
||
|
|
||
|
now := time.Now().Unix()
|
||
|
binary.BigEndian.PutUint32(outData[0:4], uint32(now))
|
||
|
|
||
|
rand.Read(outData[4 : 4+18])
|
||
|
|
||
|
hash := t.hmacSHA1(outData[:outSize-ssr.ObfsHMACSHA1Len])
|
||
|
copy(outData[outSize-ssr.ObfsHMACSHA1Len:], hash)
|
||
|
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (t *tls12TicketAuth) hmacSHA1(data []byte) []byte {
|
||
|
key := make([]byte, t.KeyLen+32)
|
||
|
copy(key, t.Key)
|
||
|
copy(key[t.KeyLen:], t.data.localClientID[:])
|
||
|
|
||
|
sha1Data := tools.HmacSHA1(key, data)
|
||
|
return sha1Data[:ssr.ObfsHMACSHA1Len]
|
||
|
}
|
||
|
|
||
|
func (t *tls12TicketAuth) sni(u string) []byte {
|
||
|
bURL := []byte(u)
|
||
|
length := len(bURL)
|
||
|
ret := make([]byte, length+9)
|
||
|
copy(ret[9:9+length], bURL)
|
||
|
binary.BigEndian.PutUint16(ret[7:], uint16(length&0xFFFF))
|
||
|
length += 3
|
||
|
binary.BigEndian.PutUint16(ret[4:], uint16(length&0xFFFF))
|
||
|
length += 2
|
||
|
binary.BigEndian.PutUint16(ret[2:], uint16(length&0xFFFF))
|
||
|
return ret
|
||
|
}
|