|  | @@ -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())
 |