|  | @@ -11,6 +11,7 @@ import (
 | 
	
		
			
				|  |  |  	"golang.org/x/crypto/chacha20poly1305"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	"v2ray.com/core/app/log"
 | 
	
		
			
				|  |  | +	"v2ray.com/core/common"
 | 
	
		
			
				|  |  |  	"v2ray.com/core/common/buf"
 | 
	
		
			
				|  |  |  	"v2ray.com/core/common/crypto"
 | 
	
		
			
				|  |  |  	"v2ray.com/core/common/dice"
 | 
	
	
		
			
				|  | @@ -43,7 +44,7 @@ type ClientSession struct {
 | 
	
		
			
				|  |  |  // NewClientSession creates a new ClientSession.
 | 
	
		
			
				|  |  |  func NewClientSession(idHash protocol.IDHash) *ClientSession {
 | 
	
		
			
				|  |  |  	randomBytes := make([]byte, 33) // 16 + 16 + 1
 | 
	
		
			
				|  |  | -	rand.Read(randomBytes)
 | 
	
		
			
				|  |  | +	common.Must2(rand.Read(randomBytes))
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	session := &ClientSession{}
 | 
	
		
			
				|  |  |  	session.requestBodyKey = randomBytes[:16]
 | 
	
	
		
			
				|  | @@ -58,22 +59,22 @@ func NewClientSession(idHash protocol.IDHash) *ClientSession {
 | 
	
		
			
				|  |  |  	return session
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -func (v *ClientSession) EncodeRequestHeader(header *protocol.RequestHeader, writer io.Writer) {
 | 
	
		
			
				|  |  | +func (c *ClientSession) EncodeRequestHeader(header *protocol.RequestHeader, writer io.Writer) {
 | 
	
		
			
				|  |  |  	timestamp := protocol.NewTimestampGenerator(protocol.NowTime(), 30)()
 | 
	
		
			
				|  |  |  	account, err := header.User.GetTypedAccount()
 | 
	
		
			
				|  |  |  	if err != nil {
 | 
	
		
			
				|  |  |  		log.Trace(newError("failed to get user account: ", err).AtError())
 | 
	
		
			
				|  |  |  		return
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | -	idHash := v.idHash(account.(*vmess.InternalAccount).AnyValidID().Bytes())
 | 
	
		
			
				|  |  | -	idHash.Write(timestamp.Bytes(nil))
 | 
	
		
			
				|  |  | -	writer.Write(idHash.Sum(nil))
 | 
	
		
			
				|  |  | +	idHash := c.idHash(account.(*vmess.InternalAccount).AnyValidID().Bytes())
 | 
	
		
			
				|  |  | +	common.Must2(idHash.Write(timestamp.Bytes(nil)))
 | 
	
		
			
				|  |  | +	common.Must2(writer.Write(idHash.Sum(nil)))
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	buffer := make([]byte, 0, 512)
 | 
	
		
			
				|  |  |  	buffer = append(buffer, Version)
 | 
	
		
			
				|  |  | -	buffer = append(buffer, v.requestBodyIV...)
 | 
	
		
			
				|  |  | -	buffer = append(buffer, v.requestBodyKey...)
 | 
	
		
			
				|  |  | -	buffer = append(buffer, v.responseHeader, byte(header.Option))
 | 
	
		
			
				|  |  | +	buffer = append(buffer, c.requestBodyIV...)
 | 
	
		
			
				|  |  | +	buffer = append(buffer, c.requestBodyKey...)
 | 
	
		
			
				|  |  | +	buffer = append(buffer, c.responseHeader, byte(header.Option))
 | 
	
		
			
				|  |  |  	padingLen := dice.Roll(16)
 | 
	
		
			
				|  |  |  	if header.Security.Is(protocol.SecurityType_LEGACY) {
 | 
	
		
			
				|  |  |  		// Disable padding in legacy mode for a smooth transition.
 | 
	
	
		
			
				|  | @@ -100,29 +101,27 @@ func (v *ClientSession) EncodeRequestHeader(header *protocol.RequestHeader, writ
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	if padingLen > 0 {
 | 
	
		
			
				|  |  |  		pading := make([]byte, padingLen)
 | 
	
		
			
				|  |  | -		rand.Read(pading)
 | 
	
		
			
				|  |  | +		common.Must2(rand.Read(pading))
 | 
	
		
			
				|  |  |  		buffer = append(buffer, pading...)
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	fnv1a := fnv.New32a()
 | 
	
		
			
				|  |  | -	fnv1a.Write(buffer)
 | 
	
		
			
				|  |  | +	common.Must2(fnv1a.Write(buffer))
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	buffer = fnv1a.Sum(buffer)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	timestampHash := md5.New()
 | 
	
		
			
				|  |  | -	timestampHash.Write(hashTimestamp(timestamp))
 | 
	
		
			
				|  |  | +	common.Must2(timestampHash.Write(hashTimestamp(timestamp)))
 | 
	
		
			
				|  |  |  	iv := timestampHash.Sum(nil)
 | 
	
		
			
				|  |  |  	aesStream := crypto.NewAesEncryptionStream(account.(*vmess.InternalAccount).ID.CmdKey(), iv)
 | 
	
		
			
				|  |  |  	aesStream.XORKeyStream(buffer, buffer)
 | 
	
		
			
				|  |  | -	writer.Write(buffer)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	return
 | 
	
		
			
				|  |  | +	common.Must2(writer.Write(buffer))
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -func (v *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, writer io.Writer) buf.Writer {
 | 
	
		
			
				|  |  | +func (c *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, writer io.Writer) buf.Writer {
 | 
	
		
			
				|  |  |  	var sizeParser crypto.ChunkSizeEncoder = crypto.PlainChunkSizeParser{}
 | 
	
		
			
				|  |  |  	if request.Option.Has(protocol.RequestOptionChunkMasking) {
 | 
	
		
			
				|  |  | -		sizeParser = NewShakeSizeParser(v.requestBodyIV)
 | 
	
		
			
				|  |  | +		sizeParser = NewShakeSizeParser(c.requestBodyIV)
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  	if request.Security.Is(protocol.SecurityType_NONE) {
 | 
	
		
			
				|  |  |  		if request.Option.Has(protocol.RequestOptionChunkStream) {
 | 
	
	
		
			
				|  | @@ -141,7 +140,7 @@ func (v *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, write
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	if request.Security.Is(protocol.SecurityType_LEGACY) {
 | 
	
		
			
				|  |  | -		aesStream := crypto.NewAesEncryptionStream(v.requestBodyKey, v.requestBodyIV)
 | 
	
		
			
				|  |  | +		aesStream := crypto.NewAesEncryptionStream(c.requestBodyKey, c.requestBodyIV)
 | 
	
		
			
				|  |  |  		cryptionWriter := crypto.NewCryptionWriter(aesStream, writer)
 | 
	
		
			
				|  |  |  		if request.Option.Has(protocol.RequestOptionChunkStream) {
 | 
	
		
			
				|  |  |  			auth := &crypto.AEADAuthenticator{
 | 
	
	
		
			
				|  | @@ -156,13 +155,13 @@ func (v *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, write
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	if request.Security.Is(protocol.SecurityType_AES128_GCM) {
 | 
	
		
			
				|  |  | -		block, _ := aes.NewCipher(v.requestBodyKey)
 | 
	
		
			
				|  |  | +		block, _ := aes.NewCipher(c.requestBodyKey)
 | 
	
		
			
				|  |  |  		aead, _ := cipher.NewGCM(block)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		auth := &crypto.AEADAuthenticator{
 | 
	
		
			
				|  |  |  			AEAD: aead,
 | 
	
		
			
				|  |  |  			NonceGenerator: &ChunkNonceGenerator{
 | 
	
		
			
				|  |  | -				Nonce: append([]byte(nil), v.requestBodyIV...),
 | 
	
		
			
				|  |  | +				Nonce: append([]byte(nil), c.requestBodyIV...),
 | 
	
		
			
				|  |  |  				Size:  aead.NonceSize(),
 | 
	
		
			
				|  |  |  			},
 | 
	
		
			
				|  |  |  			AdditionalDataGenerator: crypto.NoOpBytesGenerator{},
 | 
	
	
		
			
				|  | @@ -171,12 +170,12 @@ func (v *ClientSession) EncodeRequestBody(request *protocol.RequestHeader, write
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	if request.Security.Is(protocol.SecurityType_CHACHA20_POLY1305) {
 | 
	
		
			
				|  |  | -		aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(v.requestBodyKey))
 | 
	
		
			
				|  |  | +		aead, _ := chacha20poly1305.New(GenerateChacha20Poly1305Key(c.requestBodyKey))
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  		auth := &crypto.AEADAuthenticator{
 | 
	
		
			
				|  |  |  			AEAD: aead,
 | 
	
		
			
				|  |  |  			NonceGenerator: &ChunkNonceGenerator{
 | 
	
		
			
				|  |  | -				Nonce: append([]byte(nil), v.requestBodyIV...),
 | 
	
		
			
				|  |  | +				Nonce: append([]byte(nil), c.requestBodyIV...),
 | 
	
		
			
				|  |  |  				Size:  aead.NonceSize(),
 | 
	
		
			
				|  |  |  			},
 | 
	
		
			
				|  |  |  			AdditionalDataGenerator: crypto.NoOpBytesGenerator{},
 | 
	
	
		
			
				|  | @@ -299,8 +298,8 @@ type ChunkNonceGenerator struct {
 | 
	
		
			
				|  |  |  	count uint16
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -func (v *ChunkNonceGenerator) Next() []byte {
 | 
	
		
			
				|  |  | -	serial.Uint16ToBytes(v.count, v.Nonce[:0])
 | 
	
		
			
				|  |  | -	v.count++
 | 
	
		
			
				|  |  | -	return v.Nonce[:v.Size]
 | 
	
		
			
				|  |  | +func (g *ChunkNonceGenerator) Next() []byte {
 | 
	
		
			
				|  |  | +	serial.Uint16ToBytes(g.count, g.Nonce[:0])
 | 
	
		
			
				|  |  | +	g.count++
 | 
	
		
			
				|  |  | +	return g.Nonce[:g.Size]
 | 
	
		
			
				|  |  |  }
 |