| 
					
				 | 
			
			
				@@ -85,19 +85,19 @@ func (h *SessionHistory) removeExpiredEntries() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 type ServerSession struct { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	userValidator   protocol.UserValidator 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	userValidator   *vmess.TimedUserValidator 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	sessionHistory  *SessionHistory 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	requestBodyKey  []byte 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	requestBodyIV   []byte 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	responseBodyKey []byte 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	responseBodyIV  []byte 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	responseHeader  byte 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	requestBodyKey  [16]byte 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	requestBodyIV   [16]byte 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	responseBodyKey [16]byte 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	responseBodyIV  [16]byte 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	responseWriter  io.Writer 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	responseHeader  byte 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // NewServerSession creates a new ServerSession, using the given UserValidator. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // The ServerSession instance doesn't take ownership of the validator. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-func NewServerSession(validator protocol.UserValidator, sessionHistory *SessionHistory) *ServerSession { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func NewServerSession(validator *vmess.TimedUserValidator, sessionHistory *SessionHistory) *ServerSession { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	return &ServerSession{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		userValidator:  validator, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		sessionHistory: sessionHistory, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -150,12 +150,12 @@ func (s *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.Request 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		Version: buffer.Byte(0), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	s.requestBodyIV = append([]byte(nil), buffer.BytesRange(1, 17)...)   // 16 bytes 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	s.requestBodyKey = append([]byte(nil), buffer.BytesRange(17, 33)...) // 16 bytes 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	copy(s.requestBodyIV[:], buffer.BytesRange(1, 17))   // 16 bytes 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	copy(s.requestBodyKey[:], buffer.BytesRange(17, 33)) // 16 bytes 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	var sid sessionId 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	copy(sid.user[:], vmessAccount.ID.Bytes()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	copy(sid.key[:], s.requestBodyKey) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	copy(sid.nonce[:], s.requestBodyIV) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	sid.key = s.requestBodyKey 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	sid.nonce = s.requestBodyIV 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	if !s.sessionHistory.addIfNotExits(sid) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		return nil, newError("duplicated session id, possibly under replay attack") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -227,7 +227,7 @@ func (s *ServerSession) DecodeRequestHeader(reader io.Reader) (*protocol.Request 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reader io.Reader) buf.Reader { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	var sizeParser crypto.ChunkSizeDecoder = crypto.PlainChunkSizeParser{} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	if request.Option.Has(protocol.RequestOptionChunkMasking) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		sizeParser = NewShakeSizeParser(s.requestBodyIV) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		sizeParser = NewShakeSizeParser(s.requestBodyIV[:]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	switch request.Security { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	case protocol.SecurityType_NONE: 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -246,7 +246,7 @@ func (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reade 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		return buf.NewReader(reader) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	case protocol.SecurityType_LEGACY: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		aesStream := crypto.NewAesDecryptionStream(s.requestBodyKey, s.requestBodyIV) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		aesStream := crypto.NewAesDecryptionStream(s.requestBodyKey[:], s.requestBodyIV[:]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		cryptionReader := crypto.NewCryptionReader(aesStream, reader) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		if request.Option.Has(protocol.RequestOptionChunkStream) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			auth := &crypto.AEADAuthenticator{ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -259,21 +259,21 @@ func (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reade 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		return buf.NewReader(cryptionReader) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	case protocol.SecurityType_AES128_GCM: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		block, _ := aes.NewCipher(s.requestBodyKey) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		block, _ := aes.NewCipher(s.requestBodyKey[:]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		aead, _ := cipher.NewGCM(block) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		auth := &crypto.AEADAuthenticator{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			AEAD:                    aead, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			NonceGenerator:          GenerateChunkNonce(s.requestBodyIV, uint32(aead.NonceSize())), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			NonceGenerator:          GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			AdditionalDataGenerator: crypto.GenerateEmptyBytes(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	case protocol.SecurityType_CHACHA20_POLY1305: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(s.requestBodyKey)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(s.requestBodyKey[:])) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		auth := &crypto.AEADAuthenticator{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			AEAD:                    aead, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			NonceGenerator:          GenerateChunkNonce(s.requestBodyIV, uint32(aead.NonceSize())), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			NonceGenerator:          GenerateChunkNonce(s.requestBodyIV[:], uint32(aead.NonceSize())), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			AdditionalDataGenerator: crypto.GenerateEmptyBytes(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		return crypto.NewAuthenticationReader(auth, sizeParser, reader, request.Command.TransferType()) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -283,12 +283,12 @@ func (s *ServerSession) DecodeRequestBody(request *protocol.RequestHeader, reade 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func (s *ServerSession) EncodeResponseHeader(header *protocol.ResponseHeader, writer io.Writer) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	responseBodyKey := md5.Sum(s.requestBodyKey) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	responseBodyIV := md5.Sum(s.requestBodyIV) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	s.responseBodyKey = responseBodyKey[:] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	s.responseBodyIV = responseBodyIV[:] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	responseBodyKey := md5.Sum(s.requestBodyKey[:]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	responseBodyIV := md5.Sum(s.requestBodyIV[:]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	s.responseBodyKey = responseBodyKey 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	s.responseBodyIV = responseBodyIV 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	aesStream := crypto.NewAesEncryptionStream(s.responseBodyKey, s.responseBodyIV) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	aesStream := crypto.NewAesEncryptionStream(s.responseBodyKey[:], s.responseBodyIV[:]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	encryptionWriter := crypto.NewCryptionWriter(aesStream, writer) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	s.responseWriter = encryptionWriter 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -302,7 +302,7 @@ func (s *ServerSession) EncodeResponseHeader(header *protocol.ResponseHeader, wr 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func (s *ServerSession) EncodeResponseBody(request *protocol.RequestHeader, writer io.Writer) buf.Writer { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	var sizeParser crypto.ChunkSizeEncoder = crypto.PlainChunkSizeParser{} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	if request.Option.Has(protocol.RequestOptionChunkMasking) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		sizeParser = NewShakeSizeParser(s.responseBodyIV) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		sizeParser = NewShakeSizeParser(s.responseBodyIV[:]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	switch request.Security { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	case protocol.SecurityType_NONE: 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -332,21 +332,21 @@ func (s *ServerSession) EncodeResponseBody(request *protocol.RequestHeader, writ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		return buf.NewWriter(s.responseWriter) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	case protocol.SecurityType_AES128_GCM: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		block, _ := aes.NewCipher(s.responseBodyKey) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		block, _ := aes.NewCipher(s.responseBodyKey[:]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		aead, _ := cipher.NewGCM(block) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		auth := &crypto.AEADAuthenticator{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			AEAD:                    aead, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			NonceGenerator:          GenerateChunkNonce(s.responseBodyIV, uint32(aead.NonceSize())), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			NonceGenerator:          GenerateChunkNonce(s.responseBodyIV[:], uint32(aead.NonceSize())), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			AdditionalDataGenerator: crypto.GenerateEmptyBytes(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	case protocol.SecurityType_CHACHA20_POLY1305: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(s.responseBodyKey)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(s.responseBodyKey[:])) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		auth := &crypto.AEADAuthenticator{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			AEAD:                    aead, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			NonceGenerator:          GenerateChunkNonce(s.responseBodyIV, uint32(aead.NonceSize())), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			NonceGenerator:          GenerateChunkNonce(s.responseBodyIV[:], uint32(aead.NonceSize())), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			AdditionalDataGenerator: crypto.GenerateEmptyBytes(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		return crypto.NewAuthenticationWriter(auth, sizeParser, writer, request.Command.TransferType()) 
			 |