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 }