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