github.com/Asutorufa/yuhaiin@v0.3.6-0.20240502055049-7984da7023a0/pkg/net/proxy/shadowsocksr/protocol/auth_aes128_md5.go (about) 1 package protocol 2 3 import ( 4 "bytes" 5 "crypto" 6 "crypto/aes" 7 "crypto/cipher" 8 crand "crypto/rand" 9 "encoding/base64" 10 "encoding/binary" 11 "math" 12 "math/big" 13 "math/rand/v2" 14 "strconv" 15 "strings" 16 "time" 17 18 "github.com/Asutorufa/yuhaiin/pkg/log" 19 "github.com/Asutorufa/yuhaiin/pkg/net/proxy/shadowsocks/core" 20 ssr "github.com/Asutorufa/yuhaiin/pkg/net/proxy/shadowsocksr/utils" 21 "github.com/Asutorufa/yuhaiin/pkg/utils/pool" 22 "github.com/Asutorufa/yuhaiin/pkg/utils/relay" 23 "github.com/Asutorufa/yuhaiin/pkg/utils/yerror" 24 ) 25 26 func NewAuthAES128MD5(info Protocol) protocol { return newAuthAES128(info, crypto.MD5) } 27 28 func newAuthAES128(info Protocol, hash crypto.Hash) protocol { 29 a := &authAES128{ 30 salt: strings.ToLower(info.Name), 31 hmac: ssr.HMAC(hash), 32 packID: 1, 33 recvID: 1, 34 info: info, 35 } 36 a.initUserKey() 37 return a 38 } 39 40 type authAES128 struct { 41 hasSentHeader, rawTrans bool 42 recvID, packID uint32 43 uid [4]byte 44 hmac ssr.HMAC 45 userKey []byte 46 salt string 47 info Protocol 48 } 49 50 func (a *authAES128) packData(wbuf *bytes.Buffer, data []byte, fullDataSize int) { 51 dataLength := len(data) 52 if dataLength == 0 { 53 return 54 } 55 randLength := a.rndDataLen(dataLength, fullDataSize) 56 57 // 1: randLengthData Length 58 outLength := 1 + randLength + dataLength + 8 59 60 key := make([]byte, len(a.userKey)+4) 61 copy(key, a.userKey) 62 binary.LittleEndian.PutUint32(key[len(key)-4:], a.packID) 63 64 a.packID = (a.packID + 1) & 0xFFFFFFFF 65 66 // 0~1, out length 67 binary.Write(wbuf, binary.LittleEndian, uint16(outLength)) 68 69 hmacBuf := pool.GetBytes(6) 70 defer pool.PutBytes(hmacBuf) 71 72 // 2~3, hmac 73 wbuf.Write(a.hmac.HMAC(key, wbuf.Bytes()[wbuf.Len()-2:], hmacBuf)[:2]) 74 75 // 4, rand length 76 if randLength < 128 { 77 wbuf.WriteByte(byte(randLength + 1)) 78 } else { 79 // 4, magic number 255 80 wbuf.WriteByte(255) 81 // 5~6, rand length 82 binary.Write(wbuf, binary.LittleEndian, uint16(randLength+1)) 83 randLength -= 2 84 } 85 86 // 4~rand length+4, rand number 87 if _, err := relay.CopyN(wbuf, crand.Reader, int64(randLength)); err != nil { 88 log.Error("copy rand bytes failed", "err", err) 89 } 90 91 // rand length+4~out length-4, data 92 wbuf.Write(data) 93 94 start := wbuf.Len() - outLength + 4 95 // hmac 96 wbuf.Write(a.hmac.HMAC(key, wbuf.Bytes()[start:], hmacBuf)[:4]) 97 } 98 99 func (a *authAES128) initUserKey() { 100 if a.userKey != nil { 101 return 102 } 103 104 params := strings.Split(a.info.Param, ":") 105 if len(params) >= 2 { 106 userID, err := strconv.ParseUint(params[0], 10, 32) 107 if err == nil { 108 binary.LittleEndian.PutUint32(a.uid[:], uint32(userID)) 109 a.userKey = a.hmac.HASH([]byte(params[1])) 110 } 111 } 112 113 if a.userKey == nil { 114 crand.Read(a.uid[:]) 115 a.userKey = make([]byte, len(a.info.Key())) 116 copy(a.userKey, a.info.Key()) 117 } 118 } 119 120 // https://github.com/shadowsocksrr/shadowsocksr/blob/fd723a92c488d202b407323f0512987346944136/shadowsocks/obfsplugin/auth.py#L501 121 func (a *authAES128) rndDataLen(bufSize, fullBufSize int) int { 122 trapezoidRandomFLoat := func(maxVal int, d float64) int { 123 var r float64 124 if d == 0 { 125 r = rand.Float64() 126 } else { 127 s := rand.Float64() 128 a := 1 - d 129 r = (math.Sqrt(a*a+4*d*s) - a) / (2 * d) 130 } 131 132 return int(float64(maxVal) * r) 133 } 134 135 if fullBufSize >= pool.DefaultSize { 136 return 0 137 } 138 139 revLen := a.info.TcpMss - bufSize - a.GetOverhead() 140 if revLen == 0 { 141 return 0 142 } 143 if revLen < 0 { 144 if revLen > -a.info.TcpMss { 145 return trapezoidRandomFLoat(revLen+a.info.TcpMss, -0.3) 146 } 147 148 return rand.IntN(32) 149 } 150 151 if bufSize > 900 { 152 return rand.IntN(revLen) 153 } 154 155 return trapezoidRandomFLoat(revLen, -0.3) 156 } 157 158 func (a *authAES128) packAuthData(wbuf *bytes.Buffer, data []byte) { 159 dataLength := len(data) 160 if dataLength == 0 { 161 return 162 } 163 164 var randLength int 165 if dataLength > 400 { 166 randLength = rand.IntN(512) 167 } else { 168 randLength = rand.IntN(1024) 169 } 170 171 outLength := 7 + 4 + 16 + 4 + dataLength + randLength + 4 172 173 aesCipherKey := core.KDF(base64.StdEncoding.EncodeToString(a.userKey)+a.salt, 16) 174 block, err := aes.NewCipher(aesCipherKey) 175 if err != nil { 176 return 177 } 178 179 encrypt := pool.GetBytesWriter(16) 180 defer encrypt.Free() 181 182 a.info.Auth.nextAuth() 183 encrypt.WriteLittleEndianUint32(uint32(time.Now().Unix())) 184 _, _ = encrypt.Write(a.info.Auth.clientID[:]) 185 encrypt.WriteLittleEndianUint32(a.info.Auth.connectionID.Load()) 186 encrypt.WriteLittleEndianUint16(uint16(outLength)) 187 encrypt.WriteLittleEndianUint16(uint16(randLength)) 188 189 iv := make([]byte, aes.BlockSize) 190 cbc := cipher.NewCBCEncrypter(block, iv) 191 cbc.CryptBlocks(encrypt.Bytes(), encrypt.Bytes()) 192 193 key := make([]byte, a.info.IVSize()+len(a.info.Key())) 194 copy(key, a.info.IV) 195 copy(key[a.info.IVSize():], a.info.Key()) 196 197 hmacBuf := pool.GetBytes(6) 198 defer pool.PutBytes(hmacBuf) 199 200 wbuf.WriteByte(byte(yerror.Ignore(crand.Int(crand.Reader, big.NewInt(256))).Uint64())) 201 wbuf.Write(a.hmac.HMAC(key, wbuf.Bytes()[wbuf.Len()-1:], hmacBuf)[:6]) 202 wbuf.Write(a.uid[:]) 203 wbuf.Write(encrypt.Bytes()) 204 wbuf.Write(a.hmac.HMAC(key, wbuf.Bytes()[wbuf.Len()-20:], hmacBuf)[:4]) 205 _, _ = relay.CopyN(wbuf, crand.Reader, int64(randLength)) 206 wbuf.Write(data) 207 start := wbuf.Len() - outLength + 4 208 wbuf.Write(a.hmac.HMAC(a.userKey, wbuf.Bytes()[start:], hmacBuf)[:4]) 209 } 210 211 func (a *authAES128) EncryptStream(wbuf *bytes.Buffer, data []byte) (err error) { 212 dataLen := len(data) 213 214 if dataLen <= 0 { 215 return nil 216 } 217 218 if !a.hasSentHeader { 219 authLen := GetHeadSize(data, 30) + rand.IntN(32) 220 if authLen > dataLen { 221 authLen = dataLen 222 } 223 224 a.packAuthData(wbuf, data[:authLen]) 225 data = data[authLen:] 226 227 a.hasSentHeader = true 228 } 229 230 // https://github.com/shadowsocksrr/shadowsocksr/blob/fd723a92c488d202b407323f0512987346944136/shadowsocks/obfsplugin/auth.py#L459 231 const unitLen = 8100 232 for len(data) > unitLen { 233 a.packData(wbuf, data[:unitLen], dataLen) 234 data = data[unitLen:] 235 } 236 a.packData(wbuf, data, dataLen) 237 238 return nil 239 } 240 241 func (a *authAES128) DecryptStream(rbuf *bytes.Buffer, data []byte) (int, error) { 242 if a.rawTrans { 243 return rbuf.Write(data) 244 } 245 246 datalen, readLen := len(data), 0 247 248 keyLen := len(a.userKey) + 4 249 250 key := pool.GetBytesWriter(keyLen) 251 defer key.Free() 252 253 _, _ = key.Write(a.userKey) 254 255 hmacBuf := pool.GetBytes(6) 256 defer pool.PutBytes(hmacBuf) 257 258 for remain := datalen; remain > 4; remain = datalen - readLen { 259 key.Truncate(keyLen - 4) 260 key.WriteLittleEndianUint32(a.recvID) 261 if !bytes.Equal(a.hmac.HMAC(key.Bytes(), data[0:2], hmacBuf)[:2], data[2:4]) { 262 return 0, ssr.ErrAuthAES128IncorrectHMAC 263 } 264 265 clen := int(binary.LittleEndian.Uint16(data[0:2])) 266 cdlen := clen - 4 267 268 if clen >= 8192 || clen < 7 { 269 a.rawTrans = true 270 return 0, ssr.ErrAuthAES128DataLengthError 271 } 272 273 if clen > remain { 274 break 275 } 276 277 if !bytes.Equal(a.hmac.HMAC(key.Bytes(), data[:cdlen], hmacBuf)[:4], data[cdlen:clen]) { 278 a.rawTrans = true 279 return 0, ssr.ErrAuthAES128IncorrectChecksum 280 } 281 282 a.recvID = (a.recvID + 1) & 0xFFFFFFFF 283 284 pos := int(data[4]) 285 if pos >= 255 { 286 pos = int(binary.LittleEndian.Uint16(data[5:7])) 287 } 288 pos += 4 289 290 if pos > cdlen { 291 return 0, ssr.ErrAuthAES128PosOutOfRange 292 } 293 294 rbuf.Write(data[pos:cdlen]) 295 296 data, readLen = data[clen:], readLen+clen 297 } 298 299 return readLen, nil 300 } 301 302 // https://github.com/shadowsocksrr/shadowsocksr/blob/fd723a92c488d202b407323f0512987346944136/shadowsocks/obfsplugin/auth.py#L749 303 func (a *authAES128) EncryptPacket(b []byte) ([]byte, error) { 304 hmacBuf := pool.GetBytes(6) 305 defer pool.PutBytes(hmacBuf) 306 307 wbuf := make([]byte, 0, len(b)+len(a.uid)+4) 308 wbuf = append(wbuf, b...) 309 wbuf = append(wbuf, a.uid[:]...) 310 wbuf = append(wbuf, a.hmac.HMAC(a.userKey, wbuf, hmacBuf)[:4]...) 311 312 return wbuf, nil 313 } 314 315 // https://github.com/shadowsocksrr/shadowsocksr/blob/fd723a92c488d202b407323f0512987346944136/shadowsocks/obfsplugin/auth.py#L764 316 func (a *authAES128) DecryptPacket(b []byte) ([]byte, error) { 317 hmacBuf := pool.GetBytes(6) 318 defer pool.PutBytes(hmacBuf) 319 if !bytes.Equal(a.hmac.HMAC(a.info.Key(), b[:len(b)-4], hmacBuf)[:4], b[len(b)-4:]) { 320 return nil, ssr.ErrAuthAES128IncorrectChecksum 321 } 322 323 return b[:len(b)-4], nil 324 } 325 326 func (a *authAES128) GetOverhead() int { return 9 }