github.com/igoogolx/clash@v1.19.8/transport/ssr/protocol/auth_sha1_v4.go (about)

     1  package protocol
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"hash/adler32"
     7  	"hash/crc32"
     8  	"math/rand"
     9  	"net"
    10  
    11  	"github.com/igoogolx/clash/common/pool"
    12  	"github.com/igoogolx/clash/transport/ssr/tools"
    13  )
    14  
    15  func init() {
    16  	register("auth_sha1_v4", newAuthSHA1V4, 7)
    17  }
    18  
    19  type authSHA1V4 struct {
    20  	*Base
    21  	*authData
    22  	iv            []byte
    23  	hasSentHeader bool
    24  	rawTrans      bool
    25  }
    26  
    27  func newAuthSHA1V4(b *Base) Protocol {
    28  	return &authSHA1V4{Base: b, authData: &authData{}}
    29  }
    30  
    31  func (a *authSHA1V4) StreamConn(c net.Conn, iv []byte) net.Conn {
    32  	p := &authSHA1V4{Base: a.Base, authData: a.next()}
    33  	p.iv = iv
    34  	return &Conn{Conn: c, Protocol: p}
    35  }
    36  
    37  func (a *authSHA1V4) PacketConn(c net.PacketConn) net.PacketConn {
    38  	return c
    39  }
    40  
    41  func (a *authSHA1V4) Decode(dst, src *bytes.Buffer) error {
    42  	if a.rawTrans {
    43  		dst.ReadFrom(src)
    44  		return nil
    45  	}
    46  	for src.Len() > 4 {
    47  		if uint16(crc32.ChecksumIEEE(src.Bytes()[:2])&0xffff) != binary.LittleEndian.Uint16(src.Bytes()[2:4]) {
    48  			src.Reset()
    49  			return errAuthSHA1V4CRC32Error
    50  		}
    51  
    52  		length := int(binary.BigEndian.Uint16(src.Bytes()[:2]))
    53  		if length >= 8192 || length < 7 {
    54  			a.rawTrans = true
    55  			src.Reset()
    56  			return errAuthSHA1V4LengthError
    57  		}
    58  		if length > src.Len() {
    59  			break
    60  		}
    61  
    62  		if adler32.Checksum(src.Bytes()[:length-4]) != binary.LittleEndian.Uint32(src.Bytes()[length-4:length]) {
    63  			a.rawTrans = true
    64  			src.Reset()
    65  			return errAuthSHA1V4Adler32Error
    66  		}
    67  
    68  		pos := int(src.Bytes()[4])
    69  		if pos < 255 {
    70  			pos += 4
    71  		} else {
    72  			pos = int(binary.BigEndian.Uint16(src.Bytes()[5:7])) + 4
    73  		}
    74  		dst.Write(src.Bytes()[pos : length-4])
    75  		src.Next(length)
    76  	}
    77  	return nil
    78  }
    79  
    80  func (a *authSHA1V4) Encode(buf *bytes.Buffer, b []byte) error {
    81  	if !a.hasSentHeader {
    82  		dataLength := getDataLength(b)
    83  
    84  		a.packAuthData(buf, b[:dataLength])
    85  		b = b[dataLength:]
    86  
    87  		a.hasSentHeader = true
    88  	}
    89  	for len(b) > 8100 {
    90  		a.packData(buf, b[:8100])
    91  		b = b[8100:]
    92  	}
    93  	if len(b) > 0 {
    94  		a.packData(buf, b)
    95  	}
    96  
    97  	return nil
    98  }
    99  
   100  func (a *authSHA1V4) DecodePacket(b []byte) ([]byte, error) { return b, nil }
   101  
   102  func (a *authSHA1V4) EncodePacket(buf *bytes.Buffer, b []byte) error {
   103  	buf.Write(b)
   104  	return nil
   105  }
   106  
   107  func (a *authSHA1V4) packData(poolBuf *bytes.Buffer, data []byte) {
   108  	dataLength := len(data)
   109  	randDataLength := a.getRandDataLength(dataLength)
   110  	/*
   111  		2:	uint16 BigEndian packedDataLength
   112  		2:	uint16 LittleEndian crc32Data & 0xffff
   113  		3:	maxRandDataLengthPrefix (min:1)
   114  		4:	adler32Data
   115  	*/
   116  	packedDataLength := 2 + 2 + 3 + randDataLength + dataLength + 4
   117  	if randDataLength < 128 {
   118  		packedDataLength -= 2
   119  	}
   120  
   121  	binary.Write(poolBuf, binary.BigEndian, uint16(packedDataLength))
   122  	binary.Write(poolBuf, binary.LittleEndian, uint16(crc32.ChecksumIEEE(poolBuf.Bytes()[poolBuf.Len()-2:])&0xffff))
   123  	a.packRandData(poolBuf, randDataLength)
   124  	poolBuf.Write(data)
   125  	binary.Write(poolBuf, binary.LittleEndian, adler32.Checksum(poolBuf.Bytes()[poolBuf.Len()-packedDataLength+4:]))
   126  }
   127  
   128  func (a *authSHA1V4) packAuthData(poolBuf *bytes.Buffer, data []byte) {
   129  	dataLength := len(data)
   130  	randDataLength := a.getRandDataLength(12 + dataLength)
   131  	/*
   132  		2:	uint16 BigEndian packedAuthDataLength
   133  		4:	uint32 LittleEndian crc32Data
   134  		3:	maxRandDataLengthPrefix (min: 1)
   135  		12:	authDataLength
   136  		10:	hmacSHA1DataLength
   137  	*/
   138  	packedAuthDataLength := 2 + 4 + 3 + randDataLength + 12 + dataLength + 10
   139  	if randDataLength < 128 {
   140  		packedAuthDataLength -= 2
   141  	}
   142  
   143  	salt := []byte("auth_sha1_v4")
   144  	crcData := pool.Get(len(salt) + len(a.Key) + 2)
   145  	defer pool.Put(crcData)
   146  	binary.BigEndian.PutUint16(crcData, uint16(packedAuthDataLength))
   147  	copy(crcData[2:], salt)
   148  	copy(crcData[2+len(salt):], a.Key)
   149  
   150  	key := pool.Get(len(a.iv) + len(a.Key))
   151  	defer pool.Put(key)
   152  	copy(key, a.iv)
   153  	copy(key[len(a.iv):], a.Key)
   154  
   155  	poolBuf.Write(crcData[:2])
   156  	binary.Write(poolBuf, binary.LittleEndian, crc32.ChecksumIEEE(crcData))
   157  	a.packRandData(poolBuf, randDataLength)
   158  	a.putAuthData(poolBuf)
   159  	poolBuf.Write(data)
   160  	poolBuf.Write(tools.HmacSHA1(key, poolBuf.Bytes()[poolBuf.Len()-packedAuthDataLength+10:])[:10])
   161  }
   162  
   163  func (a *authSHA1V4) packRandData(poolBuf *bytes.Buffer, size int) {
   164  	if size < 128 {
   165  		poolBuf.WriteByte(byte(size + 1))
   166  		tools.AppendRandBytes(poolBuf, size)
   167  		return
   168  	}
   169  	poolBuf.WriteByte(255)
   170  	binary.Write(poolBuf, binary.BigEndian, uint16(size+3))
   171  	tools.AppendRandBytes(poolBuf, size)
   172  }
   173  
   174  func (a *authSHA1V4) getRandDataLength(size int) int {
   175  	if size > 1200 {
   176  		return 0
   177  	}
   178  	if size > 400 {
   179  		return rand.Intn(256)
   180  	}
   181  	return rand.Intn(512)
   182  }