mirror of
				https://github.com/nadoo/glider.git
				synced 2025-11-04 07:42:38 +08:00 
			
		
		
		
	vmess: support aead auth
This commit is contained in:
		
							parent
							
								
									7486373821
								
							
						
					
					
						commit
						8729908660
					
				
							
								
								
									
										136
									
								
								proxy/vmess/auth.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								proxy/vmess/auth.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,136 @@
 | 
				
			|||||||
 | 
					package vmess
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"crypto/aes"
 | 
				
			||||||
 | 
						"crypto/cipher"
 | 
				
			||||||
 | 
						"crypto/hmac"
 | 
				
			||||||
 | 
						"crypto/rand"
 | 
				
			||||||
 | 
						"crypto/sha256"
 | 
				
			||||||
 | 
						"encoding/binary"
 | 
				
			||||||
 | 
						"hash"
 | 
				
			||||||
 | 
						"hash/crc32"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// https://github.com/v2fly/v2ray-core/tree/327cbdc5cd10ee1aec6ef4dce1af027b3e277f33/proxy/vmess/aead
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						kdfSaltConstAuthIDEncryptionKey             = "AES Auth ID Encryption"
 | 
				
			||||||
 | 
						kdfSaltConstAEADRespHeaderLenKey            = "AEAD Resp Header Len Key"
 | 
				
			||||||
 | 
						kdfSaltConstAEADRespHeaderLenIV             = "AEAD Resp Header Len IV"
 | 
				
			||||||
 | 
						kdfSaltConstAEADRespHeaderPayloadKey        = "AEAD Resp Header Key"
 | 
				
			||||||
 | 
						kdfSaltConstAEADRespHeaderPayloadIV         = "AEAD Resp Header IV"
 | 
				
			||||||
 | 
						kdfSaltConstVMessAEADKDF                    = "VMess AEAD KDF"
 | 
				
			||||||
 | 
						kdfSaltConstVMessHeaderPayloadAEADKey       = "VMess Header AEAD Key"
 | 
				
			||||||
 | 
						kdfSaltConstVMessHeaderPayloadAEADIV        = "VMess Header AEAD Nonce"
 | 
				
			||||||
 | 
						kdfSaltConstVMessHeaderPayloadLengthAEADKey = "VMess Header AEAD Key_Length"
 | 
				
			||||||
 | 
						kdfSaltConstVMessHeaderPayloadLengthAEADIV  = "VMess Header AEAD Nonce_Length"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func sealVMessAEADHeader(key [16]byte, data []byte) []byte {
 | 
				
			||||||
 | 
						generatedAuthID := createAuthID(key[:], time.Now().Unix())
 | 
				
			||||||
 | 
						connectionNonce := make([]byte, 8)
 | 
				
			||||||
 | 
						rand.Read(connectionNonce)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						aeadPayloadLengthSerializedByte := make([]byte, 2)
 | 
				
			||||||
 | 
						binary.BigEndian.PutUint16(aeadPayloadLengthSerializedByte, uint16(len(data)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var payloadHeaderLengthAEADEncrypted []byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							payloadHeaderLengthAEADKey := kdf(key[:], kdfSaltConstVMessHeaderPayloadLengthAEADKey, string(generatedAuthID[:]), string(connectionNonce))[:16]
 | 
				
			||||||
 | 
							payloadHeaderLengthAEADNonce := kdf(key[:], kdfSaltConstVMessHeaderPayloadLengthAEADIV, string(generatedAuthID[:]), string(connectionNonce))[:12]
 | 
				
			||||||
 | 
							payloadHeaderLengthAEADAESBlock, _ := aes.NewCipher(payloadHeaderLengthAEADKey)
 | 
				
			||||||
 | 
							payloadHeaderAEAD, _ := cipher.NewGCM(payloadHeaderLengthAEADAESBlock)
 | 
				
			||||||
 | 
							payloadHeaderLengthAEADEncrypted = payloadHeaderAEAD.Seal(nil, payloadHeaderLengthAEADNonce, aeadPayloadLengthSerializedByte, generatedAuthID[:])
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var payloadHeaderAEADEncrypted []byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							payloadHeaderAEADKey := kdf(key[:], kdfSaltConstVMessHeaderPayloadAEADKey, string(generatedAuthID[:]), string(connectionNonce))[:16]
 | 
				
			||||||
 | 
							payloadHeaderAEADNonce := kdf(key[:], kdfSaltConstVMessHeaderPayloadAEADIV, string(generatedAuthID[:]), string(connectionNonce))[:12]
 | 
				
			||||||
 | 
							payloadHeaderAEADAESBlock, _ := aes.NewCipher(payloadHeaderAEADKey)
 | 
				
			||||||
 | 
							payloadHeaderAEAD, _ := cipher.NewGCM(payloadHeaderAEADAESBlock)
 | 
				
			||||||
 | 
							payloadHeaderAEADEncrypted = payloadHeaderAEAD.Seal(nil, payloadHeaderAEADNonce, data, generatedAuthID[:])
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var outputBuffer = &bytes.Buffer{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						outputBuffer.Write(generatedAuthID[:])
 | 
				
			||||||
 | 
						outputBuffer.Write(payloadHeaderLengthAEADEncrypted)
 | 
				
			||||||
 | 
						outputBuffer.Write(connectionNonce)
 | 
				
			||||||
 | 
						outputBuffer.Write(payloadHeaderAEADEncrypted)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return outputBuffer.Bytes()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func openVMessAEADHeader(key [16]byte, iv [16]byte, r io.Reader) ([]byte, error) {
 | 
				
			||||||
 | 
						aeadResponseHeaderLengthEncryptionKey := kdf(key[:], kdfSaltConstAEADRespHeaderLenKey)[:16]
 | 
				
			||||||
 | 
						aeadResponseHeaderLengthEncryptionIV := kdf(iv[:], kdfSaltConstAEADRespHeaderLenIV)[:12]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						aeadResponseHeaderLengthEncryptionKeyAESBlock, _ := aes.NewCipher(aeadResponseHeaderLengthEncryptionKey)
 | 
				
			||||||
 | 
						aeadResponseHeaderLengthEncryptionAEAD, _ := cipher.NewGCM(aeadResponseHeaderLengthEncryptionKeyAESBlock)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						aeadEncryptedResponseHeaderLength := make([]byte, 18)
 | 
				
			||||||
 | 
						if _, err := io.ReadFull(r, aeadEncryptedResponseHeaderLength); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						decryptedResponseHeaderLengthBinaryBuffer, err := aeadResponseHeaderLengthEncryptionAEAD.Open(nil, aeadResponseHeaderLengthEncryptionIV, aeadEncryptedResponseHeaderLength[:], nil)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						decryptedResponseHeaderLength := binary.BigEndian.Uint16(decryptedResponseHeaderLengthBinaryBuffer)
 | 
				
			||||||
 | 
						aeadResponseHeaderPayloadEncryptionKey := kdf(key[:], kdfSaltConstAEADRespHeaderPayloadKey)[:16]
 | 
				
			||||||
 | 
						aeadResponseHeaderPayloadEncryptionIV := kdf(iv[:], kdfSaltConstAEADRespHeaderPayloadIV)[:12]
 | 
				
			||||||
 | 
						aeadResponseHeaderPayloadEncryptionKeyAESBlock, _ := aes.NewCipher(aeadResponseHeaderPayloadEncryptionKey)
 | 
				
			||||||
 | 
						aeadResponseHeaderPayloadEncryptionAEAD, _ := cipher.NewGCM(aeadResponseHeaderPayloadEncryptionKeyAESBlock)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						encryptedResponseHeaderBuffer := make([]byte, decryptedResponseHeaderLength+16)
 | 
				
			||||||
 | 
						if _, err := io.ReadFull(r, encryptedResponseHeaderBuffer); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return aeadResponseHeaderPayloadEncryptionAEAD.Open(nil, aeadResponseHeaderPayloadEncryptionIV, encryptedResponseHeaderBuffer, nil)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func kdf(key []byte, path ...string) []byte {
 | 
				
			||||||
 | 
						hmacCreator := &hMacCreator{value: []byte(kdfSaltConstVMessAEADKDF)}
 | 
				
			||||||
 | 
						for _, v := range path {
 | 
				
			||||||
 | 
							hmacCreator = &hMacCreator{value: []byte(v), parent: hmacCreator}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						hmacf := hmacCreator.Create()
 | 
				
			||||||
 | 
						hmacf.Write(key)
 | 
				
			||||||
 | 
						return hmacf.Sum(nil)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type hMacCreator struct {
 | 
				
			||||||
 | 
						parent *hMacCreator
 | 
				
			||||||
 | 
						value  []byte
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (h *hMacCreator) Create() hash.Hash {
 | 
				
			||||||
 | 
						if h.parent == nil {
 | 
				
			||||||
 | 
							return hmac.New(sha256.New, h.value)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return hmac.New(h.parent.Create, h.value)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func createAuthID(cmdKey []byte, time int64) [16]byte {
 | 
				
			||||||
 | 
						buf := &bytes.Buffer{}
 | 
				
			||||||
 | 
						binary.Write(buf, binary.BigEndian, time)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						random := make([]byte, 4)
 | 
				
			||||||
 | 
						rand.Read(random)
 | 
				
			||||||
 | 
						buf.Write(random)
 | 
				
			||||||
 | 
						zero := crc32.ChecksumIEEE(buf.Bytes())
 | 
				
			||||||
 | 
						binary.Write(buf, binary.BigEndian, zero)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						aesBlock, _ := aes.NewCipher(kdf(cmdKey[:], kdfSaltConstAuthIDEncryptionKey)[:16])
 | 
				
			||||||
 | 
						var result [16]byte
 | 
				
			||||||
 | 
						aesBlock.Encrypt(result[:], buf.Bytes())
 | 
				
			||||||
 | 
						return result
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -5,6 +5,7 @@ import (
 | 
				
			|||||||
	"crypto/cipher"
 | 
						"crypto/cipher"
 | 
				
			||||||
	"crypto/hmac"
 | 
						"crypto/hmac"
 | 
				
			||||||
	"crypto/md5"
 | 
						"crypto/md5"
 | 
				
			||||||
 | 
						"crypto/sha256"
 | 
				
			||||||
	"encoding/binary"
 | 
						"encoding/binary"
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"hash/fnv"
 | 
						"hash/fnv"
 | 
				
			||||||
@ -17,6 +18,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"golang.org/x/crypto/chacha20poly1305"
 | 
						"golang.org/x/crypto/chacha20poly1305"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/nadoo/glider/log"
 | 
				
			||||||
	"github.com/nadoo/glider/pool"
 | 
						"github.com/nadoo/glider/pool"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -49,6 +51,7 @@ type Client struct {
 | 
				
			|||||||
	users    []*User
 | 
						users    []*User
 | 
				
			||||||
	count    int
 | 
						count    int
 | 
				
			||||||
	opt      byte
 | 
						opt      byte
 | 
				
			||||||
 | 
						aead     bool
 | 
				
			||||||
	security byte
 | 
						security byte
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -56,6 +59,7 @@ type Client struct {
 | 
				
			|||||||
type Conn struct {
 | 
					type Conn struct {
 | 
				
			||||||
	user     *User
 | 
						user     *User
 | 
				
			||||||
	opt      byte
 | 
						opt      byte
 | 
				
			||||||
 | 
						aead     bool
 | 
				
			||||||
	security byte
 | 
						security byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	atyp Atyp
 | 
						atyp Atyp
 | 
				
			||||||
@ -74,7 +78,7 @@ type Conn struct {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewClient returns a new vmess client.
 | 
					// NewClient returns a new vmess client.
 | 
				
			||||||
func NewClient(uuidStr, security string, alterID int) (*Client, error) {
 | 
					func NewClient(uuidStr, security string, alterID int, aead bool) (*Client, error) {
 | 
				
			||||||
	uuid, err := StrToUUID(uuidStr)
 | 
						uuid, err := StrToUUID(uuidStr)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
@ -87,6 +91,7 @@ func NewClient(uuidStr, security string, alterID int) (*Client, error) {
 | 
				
			|||||||
	c.count = len(c.users)
 | 
						c.count = len(c.users)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c.opt = OptChunkStream
 | 
						c.opt = OptChunkStream
 | 
				
			||||||
 | 
						c.aead = aead
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	security = strings.ToLower(security)
 | 
						security = strings.ToLower(security)
 | 
				
			||||||
	switch security {
 | 
						switch security {
 | 
				
			||||||
@ -114,7 +119,7 @@ func NewClient(uuidStr, security string, alterID int) (*Client, error) {
 | 
				
			|||||||
// NewConn returns a new vmess conn.
 | 
					// NewConn returns a new vmess conn.
 | 
				
			||||||
func (c *Client) NewConn(rc net.Conn, target string, cmd CmdType) (*Conn, error) {
 | 
					func (c *Client) NewConn(rc net.Conn, target string, cmd CmdType) (*Conn, error) {
 | 
				
			||||||
	r := rand.Intn(c.count)
 | 
						r := rand.Intn(c.count)
 | 
				
			||||||
	conn := &Conn{user: c.users[r], opt: c.opt, security: c.security, Conn: rc}
 | 
						conn := &Conn{user: c.users[r], opt: c.opt, aead: c.aead, security: c.security, Conn: rc}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var err error
 | 
						var err error
 | 
				
			||||||
	conn.atyp, conn.addr, conn.port, err = ParseAddr(target)
 | 
						conn.atyp, conn.addr, conn.port, err = ParseAddr(target)
 | 
				
			||||||
@ -130,14 +135,21 @@ func (c *Client) NewConn(rc net.Conn, target string, cmd CmdType) (*Conn, error)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	conn.reqRespV = byte(rand.Intn(1 << 8))
 | 
						conn.reqRespV = byte(rand.Intn(1 << 8))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if conn.aead {
 | 
				
			||||||
 | 
							bodyIV := sha256.Sum256(conn.reqBodyIV[:])
 | 
				
			||||||
 | 
							bodyKey := sha256.Sum256(conn.reqBodyKey[:])
 | 
				
			||||||
 | 
							copy(conn.respBodyIV[:], bodyIV[:16])
 | 
				
			||||||
 | 
							copy(conn.respBodyKey[:], bodyKey[:16])
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
		conn.respBodyIV = md5.Sum(conn.reqBodyIV[:])
 | 
							conn.respBodyIV = md5.Sum(conn.reqBodyIV[:])
 | 
				
			||||||
		conn.respBodyKey = md5.Sum(conn.reqBodyKey[:])
 | 
							conn.respBodyKey = md5.Sum(conn.reqBodyKey[:])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Auth
 | 
							// MD5 Auth
 | 
				
			||||||
		err = conn.Auth()
 | 
							err = conn.Auth()
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Request
 | 
						// Request
 | 
				
			||||||
	err = conn.Request(cmd)
 | 
						err = conn.Request(cmd)
 | 
				
			||||||
@ -183,11 +195,7 @@ func (c *Conn) Request(cmd CmdType) error {
 | 
				
			|||||||
	buf.WriteByte(byte(cmd)) // cmd
 | 
						buf.WriteByte(byte(cmd)) // cmd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// target
 | 
						// target
 | 
				
			||||||
	err := binary.Write(buf, binary.BigEndian, uint16(c.port)) // port
 | 
						binary.Write(buf, binary.BigEndian, uint16(c.port)) // port
 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	buf.WriteByte(byte(c.atyp))                         // atyp
 | 
						buf.WriteByte(byte(c.atyp))                         // atyp
 | 
				
			||||||
	buf.Write(c.addr)                                   // addr
 | 
						buf.Write(c.addr)                                   // addr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -201,11 +209,14 @@ func (c *Conn) Request(cmd CmdType) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// F
 | 
						// F
 | 
				
			||||||
	fnv1a := fnv.New32a()
 | 
						fnv1a := fnv.New32a()
 | 
				
			||||||
	_, err = fnv1a.Write(buf.Bytes())
 | 
						fnv1a.Write(buf.Bytes())
 | 
				
			||||||
	if err != nil {
 | 
						buf.Write(fnv1a.Sum(nil))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if c.aead {
 | 
				
			||||||
 | 
							encHeader := sealVMessAEADHeader(c.user.CmdKey, buf.Bytes())
 | 
				
			||||||
 | 
							_, err := c.Conn.Write(encHeader)
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	buf.Write(fnv1a.Sum(nil))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	block, err := aes.NewCipher(c.user.CmdKey[:])
 | 
						block, err := aes.NewCipher(c.user.CmdKey[:])
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@ -222,29 +233,49 @@ func (c *Conn) Request(cmd CmdType) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// DecodeRespHeader decodes response header.
 | 
					// DecodeRespHeader decodes response header.
 | 
				
			||||||
func (c *Conn) DecodeRespHeader() error {
 | 
					func (c *Conn) DecodeRespHeader() error {
 | 
				
			||||||
	block, err := aes.NewCipher(c.respBodyKey[:])
 | 
						if c.aead {
 | 
				
			||||||
 | 
							buf, err := openVMessAEADHeader(c.respBodyKey, c.respBodyIV, c.Conn)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	stream := cipher.NewCFBDecrypter(block, c.respBodyIV[:])
 | 
							if len(buf) < 4 {
 | 
				
			||||||
 | 
								return errors.New("unexpected buffer length")
 | 
				
			||||||
	b := pool.GetBuffer(4)
 | 
					 | 
				
			||||||
	defer pool.PutBuffer(b)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	_, err = io.ReadFull(c.Conn, b)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	stream.XORKeyStream(b, b)
 | 
							if buf[0] != c.reqRespV {
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if b[0] != c.reqRespV {
 | 
					 | 
				
			||||||
			return errors.New("unexpected response header")
 | 
								return errors.New("unexpected response header")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// TODO: Dynamic port support
 | 
							// TODO: Dynamic port support
 | 
				
			||||||
	if b[2] != 0 {
 | 
							if buf[2] != 0 {
 | 
				
			||||||
 | 
								// dataLen := int32(buf[3])
 | 
				
			||||||
 | 
								return errors.New("dynamic port is not supported now")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						block, err := aes.NewCipher(c.respBodyKey[:])
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						stream := cipher.NewCFBDecrypter(block, c.respBodyIV[:])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buf := pool.GetBuffer(4)
 | 
				
			||||||
 | 
						defer pool.PutBuffer(buf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, err = io.ReadFull(c.Conn, buf)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						stream.XORKeyStream(buf, buf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if buf[0] != c.reqRespV {
 | 
				
			||||||
 | 
							return errors.New("unexpected response header")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: Dynamic port support
 | 
				
			||||||
 | 
						if buf[2] != 0 {
 | 
				
			||||||
		// dataLen := int32(buf[3])
 | 
							// dataLen := int32(buf[3])
 | 
				
			||||||
		return errors.New("dynamic port is not supported now")
 | 
							return errors.New("dynamic port is not supported now")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -290,6 +321,7 @@ func (c *Conn) Read(b []byte) (n int, err error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	err = c.DecodeRespHeader()
 | 
						err = c.DecodeRespHeader()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.F("[vmess] DecodeRespHeader error: %s", err)
 | 
				
			||||||
		return 0, err
 | 
							return 0, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -15,6 +15,7 @@ type VMess struct {
 | 
				
			|||||||
	addr   string
 | 
						addr   string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uuid     string
 | 
						uuid     string
 | 
				
			||||||
 | 
						aead     bool
 | 
				
			||||||
	alterID  int
 | 
						alterID  int
 | 
				
			||||||
	security string
 | 
						security string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -45,7 +46,7 @@ func NewVMess(s string, d proxy.Dialer) (*VMess, error) {
 | 
				
			|||||||
	query := u.Query()
 | 
						query := u.Query()
 | 
				
			||||||
	aid := query.Get("alterID")
 | 
						aid := query.Get("alterID")
 | 
				
			||||||
	if aid == "" {
 | 
						if aid == "" {
 | 
				
			||||||
		aid = "1"
 | 
							aid = "0"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	alterID, err := strconv.ParseUint(aid, 10, 32)
 | 
						alterID, err := strconv.ParseUint(aid, 10, 32)
 | 
				
			||||||
@ -54,7 +55,8 @@ func NewVMess(s string, d proxy.Dialer) (*VMess, error) {
 | 
				
			|||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	client, err := NewClient(uuid, security, int(alterID))
 | 
						aead := alterID == 0
 | 
				
			||||||
 | 
						client, err := NewClient(uuid, security, int(alterID), aead)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.F("create vmess client err: %s", err)
 | 
							log.F("create vmess client err: %s", err)
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user