github.com/chwjbn/xclash@v0.2.0/transport/ssr/protocol/auth_chain_a.go (about)

     1  package protocol
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/cipher"
     6  	"crypto/rand"
     7  	"crypto/rc4"
     8  	"encoding/base64"
     9  	"encoding/binary"
    10  	"net"
    11  	"strconv"
    12  	"strings"
    13  
    14  	"github.com/chwjbn/xclash/common/pool"
    15  	"github.com/chwjbn/xclash/log"
    16  	"github.com/chwjbn/xclash/transport/ssr/tools"
    17  
    18  	"github.com/Dreamacro/go-shadowsocks2/core"
    19  )
    20  
    21  func init() {
    22  	register("auth_chain_a", newAuthChainA, 4)
    23  }
    24  
    25  type randDataLengthMethod func(int, []byte, *tools.XorShift128Plus) int
    26  
    27  type authChainA struct {
    28  	*Base
    29  	*authData
    30  	*userData
    31  	iv             []byte
    32  	salt           string
    33  	hasSentHeader  bool
    34  	rawTrans       bool
    35  	lastClientHash []byte
    36  	lastServerHash []byte
    37  	encrypter      cipher.Stream
    38  	decrypter      cipher.Stream
    39  	randomClient   tools.XorShift128Plus
    40  	randomServer   tools.XorShift128Plus
    41  	randDataLength randDataLengthMethod
    42  	packID         uint32
    43  	recvID         uint32
    44  }
    45  
    46  func newAuthChainA(b *Base) Protocol {
    47  	a := &authChainA{
    48  		Base:     b,
    49  		authData: &authData{},
    50  		userData: &userData{},
    51  		salt:     "auth_chain_a",
    52  	}
    53  	a.initUserData()
    54  	return a
    55  }
    56  
    57  func (a *authChainA) initUserData() {
    58  	params := strings.Split(a.Param, ":")
    59  	if len(params) > 1 {
    60  		if userID, err := strconv.ParseUint(params[0], 10, 32); err == nil {
    61  			binary.LittleEndian.PutUint32(a.userID[:], uint32(userID))
    62  			a.userKey = []byte(params[1])
    63  		} else {
    64  			log.Warnln("Wrong protocol-param for %s, only digits are expected before ':'", a.salt)
    65  		}
    66  	}
    67  	if len(a.userKey) == 0 {
    68  		a.userKey = a.Key
    69  		rand.Read(a.userID[:])
    70  	}
    71  }
    72  
    73  func (a *authChainA) StreamConn(c net.Conn, iv []byte) net.Conn {
    74  	p := &authChainA{
    75  		Base:     a.Base,
    76  		authData: a.next(),
    77  		userData: a.userData,
    78  		salt:     a.salt,
    79  		packID:   1,
    80  		recvID:   1,
    81  	}
    82  	p.iv = iv
    83  	p.randDataLength = p.getRandLength
    84  	return &Conn{Conn: c, Protocol: p}
    85  }
    86  
    87  func (a *authChainA) PacketConn(c net.PacketConn) net.PacketConn {
    88  	p := &authChainA{
    89  		Base:     a.Base,
    90  		salt:     a.salt,
    91  		userData: a.userData,
    92  	}
    93  	return &PacketConn{PacketConn: c, Protocol: p}
    94  }
    95  
    96  func (a *authChainA) Decode(dst, src *bytes.Buffer) error {
    97  	if a.rawTrans {
    98  		dst.ReadFrom(src)
    99  		return nil
   100  	}
   101  	for src.Len() > 4 {
   102  		macKey := pool.Get(len(a.userKey) + 4)
   103  		defer pool.Put(macKey)
   104  		copy(macKey, a.userKey)
   105  		binary.LittleEndian.PutUint32(macKey[len(a.userKey):], a.recvID)
   106  
   107  		dataLength := int(binary.LittleEndian.Uint16(src.Bytes()[:2]) ^ binary.LittleEndian.Uint16(a.lastServerHash[14:16]))
   108  		randDataLength := a.randDataLength(dataLength, a.lastServerHash, &a.randomServer)
   109  		length := dataLength + randDataLength
   110  
   111  		if length >= 4096 {
   112  			a.rawTrans = true
   113  			src.Reset()
   114  			return errAuthChainLengthError
   115  		}
   116  
   117  		if 4+length > src.Len() {
   118  			break
   119  		}
   120  
   121  		serverHash := tools.HmacMD5(macKey, src.Bytes()[:length+2])
   122  		if !bytes.Equal(serverHash[:2], src.Bytes()[length+2:length+4]) {
   123  			a.rawTrans = true
   124  			src.Reset()
   125  			return errAuthChainChksumError
   126  		}
   127  		a.lastServerHash = serverHash
   128  
   129  		pos := 2
   130  		if dataLength > 0 && randDataLength > 0 {
   131  			pos += getRandStartPos(randDataLength, &a.randomServer)
   132  		}
   133  		wantedData := src.Bytes()[pos : pos+dataLength]
   134  		a.decrypter.XORKeyStream(wantedData, wantedData)
   135  		if a.recvID == 1 {
   136  			dst.Write(wantedData[2:])
   137  		} else {
   138  			dst.Write(wantedData)
   139  		}
   140  		a.recvID++
   141  		src.Next(length + 4)
   142  	}
   143  	return nil
   144  }
   145  
   146  func (a *authChainA) Encode(buf *bytes.Buffer, b []byte) error {
   147  	if !a.hasSentHeader {
   148  		dataLength := getDataLength(b)
   149  		a.packAuthData(buf, b[:dataLength])
   150  		b = b[dataLength:]
   151  		a.hasSentHeader = true
   152  	}
   153  	for len(b) > 2800 {
   154  		a.packData(buf, b[:2800])
   155  		b = b[2800:]
   156  	}
   157  	if len(b) > 0 {
   158  		a.packData(buf, b)
   159  	}
   160  	return nil
   161  }
   162  
   163  func (a *authChainA) DecodePacket(b []byte) ([]byte, error) {
   164  	if len(b) < 9 {
   165  		return nil, errAuthChainLengthError
   166  	}
   167  	if !bytes.Equal(tools.HmacMD5(a.userKey, b[:len(b)-1])[:1], b[len(b)-1:]) {
   168  		return nil, errAuthChainChksumError
   169  	}
   170  	md5Data := tools.HmacMD5(a.Key, b[len(b)-8:len(b)-1])
   171  
   172  	randDataLength := udpGetRandLength(md5Data, &a.randomServer)
   173  
   174  	key := core.Kdf(base64.StdEncoding.EncodeToString(a.userKey)+base64.StdEncoding.EncodeToString(md5Data), 16)
   175  	rc4Cipher, err := rc4.NewCipher(key)
   176  	if err != nil {
   177  		return nil, err
   178  	}
   179  	wantedData := b[:len(b)-8-randDataLength]
   180  	rc4Cipher.XORKeyStream(wantedData, wantedData)
   181  	return wantedData, nil
   182  }
   183  
   184  func (a *authChainA) EncodePacket(buf *bytes.Buffer, b []byte) error {
   185  	authData := pool.Get(3)
   186  	defer pool.Put(authData)
   187  	rand.Read(authData)
   188  
   189  	md5Data := tools.HmacMD5(a.Key, authData)
   190  
   191  	randDataLength := udpGetRandLength(md5Data, &a.randomClient)
   192  
   193  	key := core.Kdf(base64.StdEncoding.EncodeToString(a.userKey)+base64.StdEncoding.EncodeToString(md5Data), 16)
   194  	rc4Cipher, err := rc4.NewCipher(key)
   195  	if err != nil {
   196  		return err
   197  	}
   198  	rc4Cipher.XORKeyStream(b, b)
   199  
   200  	buf.Write(b)
   201  	tools.AppendRandBytes(buf, randDataLength)
   202  	buf.Write(authData)
   203  	binary.Write(buf, binary.LittleEndian, binary.LittleEndian.Uint32(a.userID[:])^binary.LittleEndian.Uint32(md5Data[:4]))
   204  	buf.Write(tools.HmacMD5(a.userKey, buf.Bytes())[:1])
   205  	return nil
   206  }
   207  
   208  func (a *authChainA) packAuthData(poolBuf *bytes.Buffer, data []byte) {
   209  	/*
   210  		dataLength := len(data)
   211  		12:	checkHead(4) and hmac of checkHead(8)
   212  		4:	uint32 LittleEndian uid (uid = userID ^ last client hash)
   213  		16:	encrypted data of authdata(12), uint16 LittleEndian overhead(2) and uint16 LittleEndian number zero(2)
   214  		4:	last server hash(4)
   215  		packedAuthDataLength := 12 + 4 + 16 + 4 + dataLength
   216  	*/
   217  
   218  	macKey := pool.Get(len(a.iv) + len(a.Key))
   219  	defer pool.Put(macKey)
   220  	copy(macKey, a.iv)
   221  	copy(macKey[len(a.iv):], a.Key)
   222  
   223  	// check head
   224  	tools.AppendRandBytes(poolBuf, 4)
   225  	a.lastClientHash = tools.HmacMD5(macKey, poolBuf.Bytes())
   226  	a.initRC4Cipher()
   227  	poolBuf.Write(a.lastClientHash[:8])
   228  	// uid
   229  	binary.Write(poolBuf, binary.LittleEndian, binary.LittleEndian.Uint32(a.userID[:])^binary.LittleEndian.Uint32(a.lastClientHash[8:12]))
   230  	// encrypted data
   231  	err := a.putEncryptedData(poolBuf, a.userKey, [2]int{a.Overhead, 0}, a.salt)
   232  	if err != nil {
   233  		poolBuf.Reset()
   234  		return
   235  	}
   236  	// last server hash
   237  	a.lastServerHash = tools.HmacMD5(a.userKey, poolBuf.Bytes()[12:])
   238  	poolBuf.Write(a.lastServerHash[:4])
   239  	// packed data
   240  	a.packData(poolBuf, data)
   241  }
   242  
   243  func (a *authChainA) packData(poolBuf *bytes.Buffer, data []byte) {
   244  	a.encrypter.XORKeyStream(data, data)
   245  
   246  	macKey := pool.Get(len(a.userKey) + 4)
   247  	defer pool.Put(macKey)
   248  	copy(macKey, a.userKey)
   249  	binary.LittleEndian.PutUint32(macKey[len(a.userKey):], a.packID)
   250  	a.packID++
   251  
   252  	length := uint16(len(data)) ^ binary.LittleEndian.Uint16(a.lastClientHash[14:16])
   253  
   254  	originalLength := poolBuf.Len()
   255  	binary.Write(poolBuf, binary.LittleEndian, length)
   256  	a.putMixedRandDataAndData(poolBuf, data)
   257  	a.lastClientHash = tools.HmacMD5(macKey, poolBuf.Bytes()[originalLength:])
   258  	poolBuf.Write(a.lastClientHash[:2])
   259  }
   260  
   261  func (a *authChainA) putMixedRandDataAndData(poolBuf *bytes.Buffer, data []byte) {
   262  	randDataLength := a.randDataLength(len(data), a.lastClientHash, &a.randomClient)
   263  	if len(data) == 0 {
   264  		tools.AppendRandBytes(poolBuf, randDataLength)
   265  		return
   266  	}
   267  	if randDataLength > 0 {
   268  		startPos := getRandStartPos(randDataLength, &a.randomClient)
   269  		tools.AppendRandBytes(poolBuf, startPos)
   270  		poolBuf.Write(data)
   271  		tools.AppendRandBytes(poolBuf, randDataLength-startPos)
   272  		return
   273  	}
   274  	poolBuf.Write(data)
   275  }
   276  
   277  func getRandStartPos(length int, random *tools.XorShift128Plus) int {
   278  	if length == 0 {
   279  		return 0
   280  	}
   281  	return int(int64(random.Next()%8589934609) % int64(length))
   282  }
   283  
   284  func (a *authChainA) getRandLength(length int, lastHash []byte, random *tools.XorShift128Plus) int {
   285  	if length > 1440 {
   286  		return 0
   287  	}
   288  	random.InitFromBinAndLength(lastHash, length)
   289  	if length > 1300 {
   290  		return int(random.Next() % 31)
   291  	}
   292  	if length > 900 {
   293  		return int(random.Next() % 127)
   294  	}
   295  	if length > 400 {
   296  		return int(random.Next() % 521)
   297  	}
   298  	return int(random.Next() % 1021)
   299  }
   300  
   301  func (a *authChainA) initRC4Cipher() {
   302  	key := core.Kdf(base64.StdEncoding.EncodeToString(a.userKey)+base64.StdEncoding.EncodeToString(a.lastClientHash), 16)
   303  	a.encrypter, _ = rc4.NewCipher(key)
   304  	a.decrypter, _ = rc4.NewCipher(key)
   305  }
   306  
   307  func udpGetRandLength(lastHash []byte, random *tools.XorShift128Plus) int {
   308  	random.InitFromBin(lastHash)
   309  	return int(random.Next() % 127)
   310  }