glider/proxy/ssr/internal/protocol/auth_sha1_v4.go

227 lines
5.9 KiB
Go
Raw Normal View History

package protocol
import (
"bytes"
"encoding/binary"
"math/rand"
"time"
"github.com/nadoo/glider/proxy/ssr/internal/ssr"
"github.com/nadoo/glider/proxy/ssr/internal/tools"
)
func init() {
register("auth_sha1_v4", NewAuthSHA1v4)
}
type authSHA1v4 struct {
ssr.ServerInfo
data *AuthData
hasSentHeader bool
buffer bytes.Buffer
}
func NewAuthSHA1v4() IProtocol {
a := &authSHA1v4{}
return a
}
func (a *authSHA1v4) SetServerInfo(s *ssr.ServerInfo) {
a.ServerInfo = *s
}
func (a *authSHA1v4) GetServerInfo() (s *ssr.ServerInfo) {
return &a.ServerInfo
}
2022-01-26 23:40:49 +08:00
func (a *authSHA1v4) SetData(data any) {
if auth, ok := data.(*AuthData); ok {
a.data = auth
}
}
2022-01-26 23:40:49 +08:00
func (a *authSHA1v4) GetData() any {
if a.data == nil {
a.data = &AuthData{}
}
return a.data
}
func (a *authSHA1v4) packData(data []byte) (outData []byte) {
dataLength := len(data)
randLength := 1
if dataLength <= 1300 {
if dataLength > 400 {
randLength += rand.Intn(128)
} else {
randLength += rand.Intn(1024)
}
}
outLength := randLength + dataLength + 8
outData = make([]byte, outLength)
// 0~1, out length
binary.BigEndian.PutUint16(outData[0:2], uint16(outLength&0xFFFF))
// 2~3, crc of out length
crc32 := ssr.CalcCRC32(outData, 2, 0xFFFFFFFF)
binary.LittleEndian.PutUint16(outData[2:4], uint16(crc32&0xFFFF))
// 4, rand length
if randLength < 128 {
outData[4] = uint8(randLength & 0xFF)
} else {
outData[4] = uint8(0xFF)
binary.BigEndian.PutUint16(outData[5:7], uint16(randLength&0xFFFF))
}
// rand length+4~out length-4, data
if dataLength > 0 {
copy(outData[randLength+4:], data)
}
// out length-4~end, adler32 of full data
adler := ssr.CalcAdler32(outData[:outLength-4])
binary.LittleEndian.PutUint32(outData[outLength-4:], adler)
return outData
}
func (a *authSHA1v4) packAuthData(data []byte) (outData []byte) {
dataLength := len(data)
randLength := 1
if dataLength <= 1300 {
if dataLength > 400 {
randLength += rand.Intn(128)
} else {
randLength += rand.Intn(1024)
}
}
dataOffset := randLength + 4 + 2
outLength := dataOffset + dataLength + 12 + ssr.ObfsHMACSHA1Len
outData = make([]byte, outLength)
a.data.connectionID++
if a.data.connectionID > 0xFF000000 {
a.data.clientID = nil
}
if len(a.data.clientID) == 0 {
a.data.clientID = make([]byte, 8)
rand.Read(a.data.clientID)
b := make([]byte, 4)
rand.Read(b)
a.data.connectionID = binary.LittleEndian.Uint32(b) & 0xFFFFFF
}
// 0-1, out length
binary.BigEndian.PutUint16(outData[0:2], uint16(outLength&0xFFFF))
// 2~6, crc of out length+salt+key
salt := []byte("auth_sha1_v4")
crcData := make([]byte, len(salt)+a.KeyLen+2)
copy(crcData[0:2], outData[0:2])
copy(crcData[2:], salt)
copy(crcData[2+len(salt):], a.Key)
crc32 := ssr.CalcCRC32(crcData, len(crcData), 0xFFFFFFFF)
// 2~6, crc of out length+salt+key
binary.LittleEndian.PutUint32(outData[2:], crc32)
// 6~rand length+6, rand numbers
rand.Read(outData[dataOffset-randLength : dataOffset])
// 6, rand length
if randLength < 128 {
outData[6] = byte(randLength & 0xFF)
} else {
// 6, magic number 0xFF
outData[6] = 0xFF
// 7-8, rand length
binary.BigEndian.PutUint16(outData[7:9], uint16(randLength&0xFFFF))
}
// rand length+6~rand length+10, time stamp
now := time.Now().Unix()
binary.LittleEndian.PutUint32(outData[dataOffset:dataOffset+4], uint32(now))
// rand length+10~rand length+14, client ID
copy(outData[dataOffset+4:dataOffset+4+4], a.data.clientID[0:4])
// rand length+14~rand length+18, connection ID
binary.LittleEndian.PutUint32(outData[dataOffset+8:dataOffset+8+4], a.data.connectionID)
// rand length+18~rand length+18+data length, data
copy(outData[dataOffset+12:], data)
key := make([]byte, a.IVLen+a.KeyLen)
copy(key, a.IV)
copy(key[a.IVLen:], a.Key)
h := tools.HmacSHA1(key, outData[:outLength-ssr.ObfsHMACSHA1Len])
// out length-10~out length/rand length+18+data length~end, hmac
copy(outData[outLength-ssr.ObfsHMACSHA1Len:], h[0:ssr.ObfsHMACSHA1Len])
return outData
}
func (a *authSHA1v4) PreEncrypt(plainData []byte) (outData []byte, err error) {
a.buffer.Reset()
dataLength := len(plainData)
offset := 0
if !a.hasSentHeader && dataLength > 0 {
headSize := ssr.GetHeadSize(plainData, 30)
if headSize > dataLength {
headSize = dataLength
}
a.buffer.Write(a.packAuthData(plainData[:headSize]))
offset += headSize
dataLength -= headSize
a.hasSentHeader = true
}
const blockSize = 4096
for dataLength > blockSize {
a.buffer.Write(a.packData(plainData[offset : offset+blockSize]))
offset += blockSize
dataLength -= blockSize
}
if dataLength > 0 {
a.buffer.Write(a.packData(plainData[offset:]))
}
return a.buffer.Bytes(), nil
}
func (a *authSHA1v4) PostDecrypt(plainData []byte) (outData []byte, n int, err error) {
a.buffer.Reset()
dataLength := len(plainData)
plainLength := dataLength
for dataLength > 4 {
crc32 := ssr.CalcCRC32(plainData, 2, 0xFFFFFFFF)
if binary.LittleEndian.Uint16(plainData[2:4]) != uint16(crc32&0xFFFF) {
//common.Error("auth_sha1_v4 post decrypt data crc32 error")
return nil, 0, ssr.ErrAuthSHA1v4CRC32Error
}
length := int(binary.BigEndian.Uint16(plainData[0:2]))
if length >= 8192 || length < 8 {
//common.Error("auth_sha1_v4 post decrypt data length error")
dataLength = 0
plainData = nil
return nil, 0, ssr.ErrAuthSHA1v4DataLengthError
}
if length > dataLength {
break
}
if ssr.CheckAdler32(plainData, length) {
pos := int(plainData[4])
if pos != 0xFF {
pos += 4
} else {
pos = int(binary.BigEndian.Uint16(plainData[5:5+2])) + 4
}
outLength := length - pos - 4
a.buffer.Write(plainData[pos : pos+outLength])
dataLength -= length
plainData = plainData[length:]
} else {
//common.Error("auth_sha1_v4 post decrypt incorrect checksum")
dataLength = 0
plainData = nil
return nil, 0, ssr.ErrAuthSHA1v4IncorrectChecksum
}
}
return a.buffer.Bytes(), plainLength - dataLength, nil
}
func (a *authSHA1v4) GetOverhead() int {
return 7
}