2016-07-23 13:17:51 +02:00
package encoding
2016-02-27 00:05:53 +01:00
import (
2020-06-06 17:11:30 +08:00
"bytes"
"crypto/aes"
"crypto/cipher"
2016-02-27 00:05:53 +01:00
"crypto/md5"
2020-06-06 17:11:30 +08:00
"crypto/sha256"
2018-11-02 15:47:58 +01:00
"encoding/binary"
2016-02-27 00:05:53 +01:00
"hash/fnv"
"io"
2020-06-01 16:40:54 +08:00
"io/ioutil"
2017-02-12 13:57:36 +01:00
"sync"
"time"
2016-12-07 17:32:40 +01:00
"golang.org/x/crypto/chacha20poly1305"
2021-02-17 04:31:50 +08:00
"github.com/v2fly/v2ray-core/v4/common"
"github.com/v2fly/v2ray-core/v4/common/bitmask"
"github.com/v2fly/v2ray-core/v4/common/buf"
"github.com/v2fly/v2ray-core/v4/common/crypto"
"github.com/v2fly/v2ray-core/v4/common/dice"
"github.com/v2fly/v2ray-core/v4/common/net"
"github.com/v2fly/v2ray-core/v4/common/protocol"
"github.com/v2fly/v2ray-core/v4/common/task"
"github.com/v2fly/v2ray-core/v4/proxy/vmess"
vmessaead "github.com/v2fly/v2ray-core/v4/proxy/vmess/aead"
2016-02-27 00:05:53 +01:00
)
2020-10-11 19:22:46 +08:00
type sessionID struct {
2017-02-12 13:57:36 +01:00
user [ 16 ] byte
key [ 16 ] byte
nonce [ 16 ] byte
}
2018-04-14 15:39:09 +02:00
// SessionHistory keeps track of historical session ids, to prevent replay attacks.
2017-02-12 16:53:23 +01:00
type SessionHistory struct {
2017-02-12 13:57:36 +01:00
sync . RWMutex
2020-10-11 19:22:46 +08:00
cache map [ sessionID ] time . Time
2018-05-27 13:02:29 +02:00
task * task . Periodic
2017-02-12 13:57:36 +01:00
}
2018-04-14 15:39:09 +02:00
// NewSessionHistory creates a new SessionHistory object.
2018-02-07 16:35:22 +01:00
func NewSessionHistory ( ) * SessionHistory {
2017-02-12 16:53:23 +01:00
h := & SessionHistory {
2020-10-11 19:22:46 +08:00
cache : make ( map [ sessionID ] time . Time , 128 ) ,
2017-02-12 13:57:36 +01:00
}
2018-05-27 13:02:29 +02:00
h . task = & task . Periodic {
2018-02-08 15:39:46 +01:00
Interval : time . Second * 30 ,
2018-08-29 23:00:01 +02:00
Execute : h . removeExpiredEntries ,
2018-02-08 15:39:46 +01:00
}
2017-02-12 13:57:36 +01:00
return h
}
2018-02-08 15:39:46 +01:00
// Close implements common.Closable.
func ( h * SessionHistory ) Close ( ) error {
return h . task . Close ( )
}
2020-10-11 19:22:46 +08:00
func ( h * SessionHistory ) addIfNotExits ( session sessionID ) bool {
2017-02-12 13:57:36 +01:00
h . Lock ( )
2017-02-14 10:13:09 +01:00
2018-02-26 17:49:53 +01:00
if expire , found := h . cache [ session ] ; found && expire . After ( time . Now ( ) ) {
2018-08-29 23:00:01 +02:00
h . Unlock ( )
2018-02-26 17:49:53 +01:00
return false
2017-02-12 13:57:36 +01:00
}
2018-02-26 17:49:53 +01:00
h . cache [ session ] = time . Now ( ) . Add ( time . Minute * 3 )
2018-08-29 23:00:01 +02:00
h . Unlock ( )
common . Must ( h . task . Start ( ) )
2018-02-26 17:49:53 +01:00
return true
2017-02-12 13:57:36 +01:00
}
2018-08-29 23:00:01 +02:00
func ( h * SessionHistory ) removeExpiredEntries ( ) error {
2018-02-07 16:35:22 +01:00
now := time . Now ( )
2017-02-14 10:13:09 +01:00
2018-02-07 16:35:22 +01:00
h . Lock ( )
defer h . Unlock ( )
2018-05-31 12:05:25 +02:00
if len ( h . cache ) == 0 {
2018-08-29 23:00:01 +02:00
return newError ( "nothing to do" )
2018-05-31 12:05:25 +02:00
}
2018-02-07 16:35:22 +01:00
for session , expire := range h . cache {
if expire . Before ( now ) {
2017-02-12 13:57:36 +01:00
delete ( h . cache , session )
}
2018-02-07 16:35:22 +01:00
}
2018-04-07 23:07:30 +02:00
if len ( h . cache ) == 0 {
2020-10-11 19:22:46 +08:00
h . cache = make ( map [ sessionID ] time . Time , 128 )
2018-04-07 23:07:30 +02:00
}
2018-08-29 23:00:01 +02:00
return nil
2017-02-12 13:57:36 +01:00
}
2018-04-14 15:39:09 +02:00
// ServerSession keeps information for a session in VMess server.
2016-02-27 00:05:53 +01:00
type ServerSession struct {
2018-04-14 15:05:49 +02:00
userValidator * vmess . TimedUserValidator
2017-02-12 16:53:23 +01:00
sessionHistory * SessionHistory
2018-04-14 15:05:49 +02:00
requestBodyKey [ 16 ] byte
requestBodyIV [ 16 ] byte
responseBodyKey [ 16 ] byte
responseBodyIV [ 16 ] byte
2016-02-27 00:05:53 +01:00
responseWriter io . Writer
2018-04-14 15:05:49 +02:00
responseHeader byte
2020-06-06 17:11:30 +08:00
isAEADRequest bool
isAEADForced bool
2016-02-27 00:05:53 +01:00
}
2016-04-28 22:31:33 +02:00
// NewServerSession creates a new ServerSession, using the given UserValidator.
// The ServerSession instance doesn't take ownership of the validator.
2018-04-14 15:05:49 +02:00
func NewServerSession ( validator * vmess . TimedUserValidator , sessionHistory * SessionHistory ) * ServerSession {
2018-09-14 16:51:46 +02:00
return & ServerSession {
userValidator : validator ,
sessionHistory : sessionHistory ,
}
2016-02-27 17:28:21 +01:00
}
2021-02-08 18:08:01 +08:00
// SetAEADForced sets isAEADForced for a ServerSession.
func ( s * ServerSession ) SetAEADForced ( isAEADForced bool ) {
s . isAEADForced = isAEADForced
}
2018-02-23 12:13:02 +01:00
func parseSecurityType ( b byte ) protocol . SecurityType {
if _ , f := protocol . SecurityType_name [ int32 ( b ) ] ; f {
2018-03-06 10:59:37 +01:00
st := protocol . SecurityType ( b )
// For backward compatibility.
if st == protocol . SecurityType_UNKNOWN {
st = protocol . SecurityType_LEGACY
}
return st
2018-02-23 12:13:02 +01:00
}
return protocol . SecurityType_UNKNOWN
}
2018-04-14 15:39:09 +02:00
// DecodeRequestHeader decodes and returns (if successful) a RequestHeader from an input stream.
2017-07-25 22:21:59 +02:00
func ( s * ServerSession ) DecodeRequestHeader ( reader io . Reader ) ( * protocol . RequestHeader , error ) {
2017-10-27 21:11:45 +02:00
buffer := buf . New ( )
2020-06-02 14:47:54 +08:00
behaviorRand := dice . NewDeterministicDice ( int64 ( s . userValidator . GetBehaviorSeed ( ) ) )
2020-06-02 18:18:31 +08:00
BaseDrainSize := behaviorRand . Roll ( 3266 )
RandDrainMax := behaviorRand . Roll ( 64 ) + 1
RandDrainRolled := dice . Roll ( RandDrainMax )
DrainSize := BaseDrainSize + 16 + 38 + RandDrainRolled
2020-06-02 14:47:54 +08:00
readSizeRemain := DrainSize
drainConnection := func ( e error ) error {
2020-10-11 19:22:46 +08:00
// We read a deterministic generated length of data before closing the connection to offset padding read pattern
2020-06-02 14:47:54 +08:00
readSizeRemain -= int ( buffer . Len ( ) )
if readSizeRemain > 0 {
err := s . DrainConnN ( reader , readSizeRemain )
if err != nil {
2020-06-02 18:18:31 +08:00
return newError ( "failed to drain connection DrainSize = " , BaseDrainSize , " " , RandDrainMax , " " , RandDrainRolled ) . Base ( err ) . Base ( e )
2020-06-02 14:47:54 +08:00
}
2020-06-02 18:18:31 +08:00
return newError ( "connection drained DrainSize = " , BaseDrainSize , " " , RandDrainMax , " " , RandDrainRolled ) . Base ( e )
2020-06-02 14:47:54 +08:00
}
return e
}
defer func ( ) {
buffer . Release ( )
} ( )
2016-02-27 00:05:53 +01:00
2018-11-02 15:01:33 +01:00
if _ , err := buffer . ReadFullFrom ( reader , protocol . IDBytesLen ) ; err != nil {
2017-04-09 01:43:25 +02:00
return nil , newError ( "failed to read request header" ) . Base ( err )
2016-02-27 00:05:53 +01:00
}
2020-06-06 17:11:30 +08:00
var decryptor io . Reader
var vmessAccount * vmess . MemoryAccount
2020-06-06 18:57:49 +08:00
user , foundAEAD , errorAEAD := s . userValidator . GetAEAD ( buffer . Bytes ( ) )
2020-06-06 17:11:30 +08:00
var fixedSizeAuthID [ 16 ] byte
copy ( fixedSizeAuthID [ : ] , buffer . Bytes ( ) )
2020-10-11 19:22:46 +08:00
switch {
case foundAEAD :
2020-06-06 17:11:30 +08:00
vmessAccount = user . Account . ( * vmess . MemoryAccount )
var fixedSizeCmdKey [ 16 ] byte
copy ( fixedSizeCmdKey [ : ] , vmessAccount . ID . CmdKey ( ) )
2020-10-11 19:22:46 +08:00
aeadData , shouldDrain , bytesRead , errorReason := vmessaead . OpenVMessAEADHeader ( fixedSizeCmdKey , fixedSizeAuthID , reader )
2020-06-06 17:11:30 +08:00
if errorReason != nil {
if shouldDrain {
readSizeRemain -= bytesRead
return nil , drainConnection ( newError ( "AEAD read failed" ) . Base ( errorReason ) )
}
2020-11-22 05:05:01 +08:00
return nil , drainConnection ( newError ( "AEAD read failed, drain skipped" ) . Base ( errorReason ) )
2020-06-06 17:11:30 +08:00
}
decryptor = bytes . NewReader ( aeadData )
s . isAEADRequest = true
2020-10-11 19:22:46 +08:00
2021-03-01 13:26:54 +00:00
case errorAEAD == vmessaead . ErrNotFound :
2020-06-06 17:11:30 +08:00
userLegacy , timestamp , valid , userValidationError := s . userValidator . Get ( buffer . Bytes ( ) )
if ! valid || userValidationError != nil {
return nil , drainConnection ( newError ( "invalid user" ) . Base ( userValidationError ) )
}
2021-03-01 13:26:54 +00:00
if s . isAEADForced {
return nil , drainConnection ( newError ( "invalid user: VMessAEAD is enforced and a non VMessAEAD connection is received. You can still disable this security feature with environment variable v2ray.vmess.aead.forced = false . You will not be able to enable legacy header workaround in the future." ) )
}
2021-04-05 18:50:07 +01:00
newError ( "Critical Warning: potentially invalid user: a non VMessAEAD connection is received. From 2022 Jan 1st, this kind of connection will be rejected by default. You should update or replace your client software now. " ) . AtWarning ( ) . WriteToLog ( )
2020-06-06 17:11:30 +08:00
user = userLegacy
iv := hashTimestamp ( md5 . New ( ) , timestamp )
vmessAccount = userLegacy . Account . ( * vmess . MemoryAccount )
2020-10-11 19:22:46 +08:00
aesStream := crypto . NewAesDecryptionStream ( vmessAccount . ID . CmdKey ( ) , iv )
2020-06-06 17:11:30 +08:00
decryptor = crypto . NewCryptionReader ( aesStream , reader )
2020-10-11 19:22:46 +08:00
default :
2020-06-06 18:57:49 +08:00
return nil , drainConnection ( newError ( "invalid user" ) . Base ( errorAEAD ) )
2016-02-27 00:05:53 +01:00
}
2020-06-02 14:47:54 +08:00
readSizeRemain -= int ( buffer . Len ( ) )
2018-11-02 15:01:33 +01:00
buffer . Clear ( )
if _ , err := buffer . ReadFullFrom ( decryptor , 38 ) ; err != nil {
2017-04-09 01:43:25 +02:00
return nil , newError ( "failed to read request header" ) . Base ( err )
2016-02-27 00:05:53 +01:00
}
request := & protocol . RequestHeader {
User : user ,
2017-10-27 21:11:45 +02:00
Version : buffer . Byte ( 0 ) ,
2016-02-27 00:05:53 +01:00
}
2018-04-14 15:05:49 +02:00
copy ( s . requestBodyIV [ : ] , buffer . BytesRange ( 1 , 17 ) ) // 16 bytes
copy ( s . requestBodyKey [ : ] , buffer . BytesRange ( 17 , 33 ) ) // 16 bytes
2020-10-11 19:22:46 +08:00
var sid sessionID
2017-02-12 13:57:36 +01:00
copy ( sid . user [ : ] , vmessAccount . ID . Bytes ( ) )
2018-04-14 15:05:49 +02:00
sid . key = s . requestBodyKey
sid . nonce = s . requestBodyIV
2018-02-26 17:49:53 +01:00
if ! s . sessionHistory . addIfNotExits ( sid ) {
2020-06-06 17:11:30 +08:00
if ! s . isAEADRequest {
drainErr := s . userValidator . BurnTaintFuse ( fixedSizeAuthID [ : ] )
if drainErr != nil {
return nil , drainConnection ( newError ( "duplicated session id, possibly under replay attack, and failed to taint userHash" ) . Base ( drainErr ) )
}
return nil , drainConnection ( newError ( "duplicated session id, possibly under replay attack, userHash tainted" ) )
}
2020-11-22 05:05:01 +08:00
return nil , newError ( "duplicated session id, possibly under replay attack, but this is a AEAD request" )
2017-02-12 13:57:36 +01:00
}
2017-10-27 21:11:45 +02:00
s . responseHeader = buffer . Byte ( 33 ) // 1 byte
request . Option = bitmask . Byte ( buffer . Byte ( 34 ) ) // 1 byte
2020-11-18 04:23:30 +08:00
paddingLen := int ( buffer . Byte ( 35 ) >> 4 )
2018-02-23 12:13:02 +01:00
request . Security = parseSecurityType ( buffer . Byte ( 35 ) & 0x0F )
2016-12-07 17:32:40 +01:00
// 1 bytes reserved
2017-10-27 21:11:45 +02:00
request . Command = protocol . RequestCommand ( buffer . Byte ( 37 ) )
2016-02-27 00:05:53 +01:00
2018-02-09 17:48:09 +01:00
switch request . Command {
case protocol . RequestCommandMux :
request . Address = net . DomainAddress ( "v1.mux.cool" )
request . Port = 0
2020-10-11 19:22:46 +08:00
2018-02-09 17:48:09 +01:00
case protocol . RequestCommandTCP , protocol . RequestCommandUDP :
2018-02-23 23:42:01 +01:00
if addr , port , err := addrParser . ReadAddressPort ( buffer , decryptor ) ; err == nil {
2018-02-09 17:48:09 +01:00
request . Address = addr
request . Port = port
2016-02-27 00:05:53 +01:00
}
}
2020-11-18 04:23:30 +08:00
if paddingLen > 0 {
if _ , err := buffer . ReadFullFrom ( decryptor , int32 ( paddingLen ) ) ; err != nil {
2020-06-06 17:11:30 +08:00
if ! s . isAEADRequest {
burnErr := s . userValidator . BurnTaintFuse ( fixedSizeAuthID [ : ] )
if burnErr != nil {
return nil , newError ( "failed to read padding, failed to taint userHash" ) . Base ( burnErr ) . Base ( err )
}
return nil , newError ( "failed to read padding, userHash tainted" ) . Base ( err )
}
2017-04-09 01:43:25 +02:00
return nil , newError ( "failed to read padding" ) . Base ( err )
2016-12-07 17:32:40 +01:00
}
}
2018-11-02 15:01:33 +01:00
if _ , err := buffer . ReadFullFrom ( decryptor , 4 ) ; err != nil {
2020-06-06 17:11:30 +08:00
if ! s . isAEADRequest {
burnErr := s . userValidator . BurnTaintFuse ( fixedSizeAuthID [ : ] )
if burnErr != nil {
return nil , newError ( "failed to read checksum, failed to taint userHash" ) . Base ( burnErr ) . Base ( err )
}
return nil , newError ( "failed to read checksum, userHash tainted" ) . Base ( err )
}
2017-04-09 01:43:25 +02:00
return nil , newError ( "failed to read checksum" ) . Base ( err )
2016-02-27 00:05:53 +01:00
}
fnv1a := fnv . New32a ( )
2017-10-27 21:11:45 +02:00
common . Must2 ( fnv1a . Write ( buffer . BytesTo ( - 4 ) ) )
2016-02-27 00:05:53 +01:00
actualHash := fnv1a . Sum32 ( )
2018-11-02 15:47:58 +01:00
expectedHash := binary . BigEndian . Uint32 ( buffer . BytesFrom ( - 4 ) )
2016-02-27 00:05:53 +01:00
if actualHash != expectedHash {
2020-06-06 17:11:30 +08:00
if ! s . isAEADRequest {
Autherr := newError ( "invalid auth, legacy userHash tainted" )
burnErr := s . userValidator . BurnTaintFuse ( fixedSizeAuthID [ : ] )
if burnErr != nil {
Autherr = newError ( "invalid auth, can't taint legacy userHash" ) . Base ( burnErr )
}
2020-10-11 19:22:46 +08:00
// It is possible that we are under attack described in https://github.com/v2ray/v2ray-core/issues/2523
2020-06-06 17:11:30 +08:00
return nil , drainConnection ( Autherr )
}
2020-11-22 05:05:01 +08:00
return nil , newError ( "invalid auth, but this is a AEAD request" )
2016-02-27 00:05:53 +01:00
}
2016-12-13 09:17:39 +01:00
if request . Address == nil {
2017-04-09 01:43:25 +02:00
return nil , newError ( "invalid remote address" )
2016-12-13 09:17:39 +01:00
}
2018-07-09 17:26:43 +02:00
if request . Security == protocol . SecurityType_UNKNOWN || request . Security == protocol . SecurityType_AUTO {
return nil , newError ( "unknown security type: " , request . Security )
}
2016-02-27 00:05:53 +01:00
return request , nil
}
2018-04-14 15:39:09 +02:00
// DecodeRequestBody returns Reader from which caller can fetch decrypted body.
2017-07-25 22:21:59 +02:00
func ( s * ServerSession ) DecodeRequestBody ( request * protocol . RequestHeader , reader io . Reader ) buf . Reader {
2017-04-23 13:30:08 +02:00
var sizeParser crypto . ChunkSizeDecoder = crypto . PlainChunkSizeParser { }
2017-02-14 14:16:43 +01:00
if request . Option . Has ( protocol . RequestOptionChunkMasking ) {
2018-04-14 15:05:49 +02:00
sizeParser = NewShakeSizeParser ( s . requestBodyIV [ : ] )
2017-02-14 14:16:43 +01:00
}
2018-11-13 09:51:55 +01:00
var padding crypto . PaddingLengthGenerator
2018-07-07 15:42:24 +02:00
if request . Option . Has ( protocol . RequestOptionGlobalPadding ) {
padding = sizeParser . ( crypto . PaddingLengthGenerator )
}
2018-02-23 12:13:02 +01:00
switch request . Security {
case protocol . SecurityType_NONE :
2016-12-07 17:32:40 +01:00
if request . Option . Has ( protocol . RequestOptionChunkStream ) {
2018-02-09 22:29:30 +01:00
if request . Command . TransferType ( ) == protocol . TransferTypeStream {
2017-05-02 00:28:16 +02:00
return crypto . NewChunkStreamReader ( sizeParser , reader )
}
auth := & crypto . AEADAuthenticator {
AEAD : new ( NoOpAuthenticator ) ,
2018-04-14 13:10:12 +02:00
NonceGenerator : crypto . GenerateEmptyBytes ( ) ,
AdditionalDataGenerator : crypto . GenerateEmptyBytes ( ) ,
2017-05-02 00:28:16 +02:00
}
2018-07-07 15:42:24 +02:00
return crypto . NewAuthenticationReader ( auth , sizeParser , reader , protocol . TransferTypePacket , padding )
2016-12-07 17:32:40 +01:00
}
2017-04-23 13:30:08 +02:00
return buf . NewReader ( reader )
2020-10-11 19:22:46 +08:00
2018-02-23 12:13:02 +01:00
case protocol . SecurityType_LEGACY :
2018-04-14 15:05:49 +02:00
aesStream := crypto . NewAesDecryptionStream ( s . requestBodyKey [ : ] , s . requestBodyIV [ : ] )
2016-12-07 17:32:40 +01:00
cryptionReader := crypto . NewCryptionReader ( aesStream , reader )
if request . Option . Has ( protocol . RequestOptionChunkStream ) {
auth := & crypto . AEADAuthenticator {
AEAD : new ( FnvAuthenticator ) ,
2018-04-14 13:10:12 +02:00
NonceGenerator : crypto . GenerateEmptyBytes ( ) ,
AdditionalDataGenerator : crypto . GenerateEmptyBytes ( ) ,
2016-12-07 17:32:40 +01:00
}
2018-07-07 15:42:24 +02:00
return crypto . NewAuthenticationReader ( auth , sizeParser , cryptionReader , request . Command . TransferType ( ) , padding )
2016-12-07 17:32:40 +01:00
}
2017-04-23 13:30:08 +02:00
return buf . NewReader ( cryptionReader )
2020-10-11 19:22:46 +08:00
2018-02-23 12:13:02 +01:00
case protocol . SecurityType_AES128_GCM :
2018-09-12 15:43:36 +02:00
aead := crypto . NewAesGcm ( s . requestBodyKey [ : ] )
2016-12-07 17:32:40 +01:00
auth := & crypto . AEADAuthenticator {
2018-04-14 13:10:12 +02:00
AEAD : aead ,
2018-04-14 15:05:49 +02:00
NonceGenerator : GenerateChunkNonce ( s . requestBodyIV [ : ] , uint32 ( aead . NonceSize ( ) ) ) ,
2018-04-14 13:10:12 +02:00
AdditionalDataGenerator : crypto . GenerateEmptyBytes ( ) ,
2016-12-07 17:32:40 +01:00
}
2018-07-07 15:42:24 +02:00
return crypto . NewAuthenticationReader ( auth , sizeParser , reader , request . Command . TransferType ( ) , padding )
2020-10-11 19:22:46 +08:00
2018-02-23 12:13:02 +01:00
case protocol . SecurityType_CHACHA20_POLY1305 :
2018-04-14 15:05:49 +02:00
aead , _ := chacha20poly1305 . New ( GenerateChacha20Poly1305Key ( s . requestBodyKey [ : ] ) )
2016-12-07 17:32:40 +01:00
auth := & crypto . AEADAuthenticator {
2018-04-14 13:10:12 +02:00
AEAD : aead ,
2018-04-14 15:05:49 +02:00
NonceGenerator : GenerateChunkNonce ( s . requestBodyIV [ : ] , uint32 ( aead . NonceSize ( ) ) ) ,
2018-04-14 13:10:12 +02:00
AdditionalDataGenerator : crypto . GenerateEmptyBytes ( ) ,
2016-12-07 17:32:40 +01:00
}
2018-07-07 15:42:24 +02:00
return crypto . NewAuthenticationReader ( auth , sizeParser , reader , request . Command . TransferType ( ) , padding )
2020-10-11 19:22:46 +08:00
2018-02-23 12:13:02 +01:00
default :
panic ( "Unknown security type." )
2016-12-07 17:32:40 +01:00
}
2016-02-27 00:05:53 +01:00
}
2018-04-14 15:39:09 +02:00
// EncodeResponseHeader writes encoded response header into the given writer.
2017-07-25 22:21:59 +02:00
func ( s * ServerSession ) EncodeResponseHeader ( header * protocol . ResponseHeader , writer io . Writer ) {
2020-06-06 17:11:30 +08:00
var encryptionWriter io . Writer
if ! s . isAEADRequest {
s . responseBodyKey = md5 . Sum ( s . requestBodyKey [ : ] )
s . responseBodyIV = md5 . Sum ( s . requestBodyIV [ : ] )
} else {
BodyKey := sha256 . Sum256 ( s . requestBodyKey [ : ] )
copy ( s . responseBodyKey [ : ] , BodyKey [ : 16 ] )
2020-09-12 16:27:40 +08:00
BodyIV := sha256 . Sum256 ( s . requestBodyIV [ : ] )
2020-06-06 17:11:30 +08:00
copy ( s . responseBodyIV [ : ] , BodyIV [ : 16 ] )
}
2016-02-27 00:05:53 +01:00
2018-04-14 15:05:49 +02:00
aesStream := crypto . NewAesEncryptionStream ( s . responseBodyKey [ : ] , s . responseBodyIV [ : ] )
2020-06-06 17:11:30 +08:00
encryptionWriter = crypto . NewCryptionWriter ( aesStream , writer )
2017-07-25 22:21:59 +02:00
s . responseWriter = encryptionWriter
2016-02-27 00:05:53 +01:00
2020-06-08 13:21:59 +08:00
aeadEncryptedHeaderBuffer := bytes . NewBuffer ( nil )
2020-06-06 17:11:30 +08:00
if s . isAEADRequest {
2020-06-08 13:21:59 +08:00
encryptionWriter = aeadEncryptedHeaderBuffer
2020-06-06 17:11:30 +08:00
}
2017-09-19 23:27:49 +02:00
common . Must2 ( encryptionWriter . Write ( [ ] byte { s . responseHeader , byte ( header . Option ) } ) )
2016-02-27 17:28:21 +01:00
err := MarshalCommand ( header . Command , encryptionWriter )
if err != nil {
2017-09-19 23:27:49 +02:00
common . Must2 ( encryptionWriter . Write ( [ ] byte { 0x00 , 0x00 } ) )
2016-02-27 17:28:21 +01:00
}
2020-06-06 17:11:30 +08:00
if s . isAEADRequest {
2020-10-11 19:22:46 +08:00
aeadResponseHeaderLengthEncryptionKey := vmessaead . KDF16 ( s . responseBodyKey [ : ] , vmessaead . KDFSaltConstAEADRespHeaderLenKey )
aeadResponseHeaderLengthEncryptionIV := vmessaead . KDF ( s . responseBodyIV [ : ] , vmessaead . KDFSaltConstAEADRespHeaderLenIV ) [ : 12 ]
2020-06-06 17:11:30 +08:00
2020-06-08 13:21:59 +08:00
aeadResponseHeaderLengthEncryptionKeyAESBlock := common . Must2 ( aes . NewCipher ( aeadResponseHeaderLengthEncryptionKey ) ) . ( cipher . Block )
aeadResponseHeaderLengthEncryptionAEAD := common . Must2 ( cipher . NewGCM ( aeadResponseHeaderLengthEncryptionKeyAESBlock ) ) . ( cipher . AEAD )
2020-06-06 17:11:30 +08:00
2020-06-08 13:21:59 +08:00
aeadResponseHeaderLengthEncryptionBuffer := bytes . NewBuffer ( nil )
2020-06-06 17:11:30 +08:00
2020-08-30 22:58:00 +08:00
decryptedResponseHeaderLengthBinaryDeserializeBuffer := uint16 ( aeadEncryptedHeaderBuffer . Len ( ) )
2020-06-06 17:11:30 +08:00
2020-06-08 13:21:59 +08:00
common . Must ( binary . Write ( aeadResponseHeaderLengthEncryptionBuffer , binary . BigEndian , decryptedResponseHeaderLengthBinaryDeserializeBuffer ) )
2020-06-06 17:11:30 +08:00
2020-06-08 13:21:59 +08:00
AEADEncryptedLength := aeadResponseHeaderLengthEncryptionAEAD . Seal ( nil , aeadResponseHeaderLengthEncryptionIV , aeadResponseHeaderLengthEncryptionBuffer . Bytes ( ) , nil )
common . Must2 ( io . Copy ( writer , bytes . NewReader ( AEADEncryptedLength ) ) )
2020-06-06 17:11:30 +08:00
2020-10-11 19:22:46 +08:00
aeadResponseHeaderPayloadEncryptionKey := vmessaead . KDF16 ( s . responseBodyKey [ : ] , vmessaead . KDFSaltConstAEADRespHeaderPayloadKey )
aeadResponseHeaderPayloadEncryptionIV := vmessaead . KDF ( s . responseBodyIV [ : ] , vmessaead . KDFSaltConstAEADRespHeaderPayloadIV ) [ : 12 ]
2020-06-06 17:11:30 +08:00
2020-06-08 13:21:59 +08:00
aeadResponseHeaderPayloadEncryptionKeyAESBlock := common . Must2 ( aes . NewCipher ( aeadResponseHeaderPayloadEncryptionKey ) ) . ( cipher . Block )
aeadResponseHeaderPayloadEncryptionAEAD := common . Must2 ( cipher . NewGCM ( aeadResponseHeaderPayloadEncryptionKeyAESBlock ) ) . ( cipher . AEAD )
2020-06-06 17:11:30 +08:00
2020-06-08 13:21:59 +08:00
aeadEncryptedHeaderPayload := aeadResponseHeaderPayloadEncryptionAEAD . Seal ( nil , aeadResponseHeaderPayloadEncryptionIV , aeadEncryptedHeaderBuffer . Bytes ( ) , nil )
common . Must2 ( io . Copy ( writer , bytes . NewReader ( aeadEncryptedHeaderPayload ) ) )
2020-06-06 17:11:30 +08:00
}
2016-02-27 16:41:21 +01:00
}
2018-04-14 15:39:09 +02:00
// EncodeResponseBody returns a Writer that auto-encrypt content written by caller.
2017-07-25 22:21:59 +02:00
func ( s * ServerSession ) EncodeResponseBody ( request * protocol . RequestHeader , writer io . Writer ) buf . Writer {
2017-04-23 13:30:08 +02:00
var sizeParser crypto . ChunkSizeEncoder = crypto . PlainChunkSizeParser { }
2017-02-14 14:16:43 +01:00
if request . Option . Has ( protocol . RequestOptionChunkMasking ) {
2018-04-14 15:05:49 +02:00
sizeParser = NewShakeSizeParser ( s . responseBodyIV [ : ] )
2017-02-14 14:16:43 +01:00
}
2018-11-13 09:51:55 +01:00
var padding crypto . PaddingLengthGenerator
2018-07-07 15:42:24 +02:00
if request . Option . Has ( protocol . RequestOptionGlobalPadding ) {
padding = sizeParser . ( crypto . PaddingLengthGenerator )
}
2018-02-23 12:13:02 +01:00
switch request . Security {
case protocol . SecurityType_NONE :
2016-12-07 17:32:40 +01:00
if request . Option . Has ( protocol . RequestOptionChunkStream ) {
2018-02-09 22:29:30 +01:00
if request . Command . TransferType ( ) == protocol . TransferTypeStream {
2017-05-02 00:28:16 +02:00
return crypto . NewChunkStreamWriter ( sizeParser , writer )
}
auth := & crypto . AEADAuthenticator {
AEAD : new ( NoOpAuthenticator ) ,
2018-04-14 13:10:12 +02:00
NonceGenerator : crypto . GenerateEmptyBytes ( ) ,
AdditionalDataGenerator : crypto . GenerateEmptyBytes ( ) ,
2017-05-02 00:28:16 +02:00
}
2018-07-07 15:42:24 +02:00
return crypto . NewAuthenticationWriter ( auth , sizeParser , writer , protocol . TransferTypePacket , padding )
2016-12-07 17:32:40 +01:00
}
2017-04-23 13:30:08 +02:00
return buf . NewWriter ( writer )
2020-10-11 19:22:46 +08:00
2018-02-23 12:13:02 +01:00
case protocol . SecurityType_LEGACY :
2016-12-07 17:32:40 +01:00
if request . Option . Has ( protocol . RequestOptionChunkStream ) {
auth := & crypto . AEADAuthenticator {
AEAD : new ( FnvAuthenticator ) ,
2018-04-14 13:10:12 +02:00
NonceGenerator : crypto . GenerateEmptyBytes ( ) ,
AdditionalDataGenerator : crypto . GenerateEmptyBytes ( ) ,
2016-12-07 17:32:40 +01:00
}
2018-07-07 15:42:24 +02:00
return crypto . NewAuthenticationWriter ( auth , sizeParser , s . responseWriter , request . Command . TransferType ( ) , padding )
2016-12-07 17:32:40 +01:00
}
2018-07-31 16:05:57 +02:00
return & buf . SequentialWriter { Writer : s . responseWriter }
2020-10-11 19:22:46 +08:00
2018-02-23 12:13:02 +01:00
case protocol . SecurityType_AES128_GCM :
2018-09-12 15:43:36 +02:00
aead := crypto . NewAesGcm ( s . responseBodyKey [ : ] )
2016-12-07 17:32:40 +01:00
auth := & crypto . AEADAuthenticator {
2018-04-14 13:10:12 +02:00
AEAD : aead ,
2018-04-14 15:05:49 +02:00
NonceGenerator : GenerateChunkNonce ( s . responseBodyIV [ : ] , uint32 ( aead . NonceSize ( ) ) ) ,
2018-04-14 13:10:12 +02:00
AdditionalDataGenerator : crypto . GenerateEmptyBytes ( ) ,
2016-12-07 17:32:40 +01:00
}
2018-07-07 15:42:24 +02:00
return crypto . NewAuthenticationWriter ( auth , sizeParser , writer , request . Command . TransferType ( ) , padding )
2020-10-11 19:22:46 +08:00
2018-02-23 12:13:02 +01:00
case protocol . SecurityType_CHACHA20_POLY1305 :
2018-04-14 15:05:49 +02:00
aead , _ := chacha20poly1305 . New ( GenerateChacha20Poly1305Key ( s . responseBodyKey [ : ] ) )
2016-12-07 17:32:40 +01:00
auth := & crypto . AEADAuthenticator {
2018-04-14 13:10:12 +02:00
AEAD : aead ,
2018-04-14 15:05:49 +02:00
NonceGenerator : GenerateChunkNonce ( s . responseBodyIV [ : ] , uint32 ( aead . NonceSize ( ) ) ) ,
2018-04-14 13:10:12 +02:00
AdditionalDataGenerator : crypto . GenerateEmptyBytes ( ) ,
2016-12-07 17:32:40 +01:00
}
2018-07-07 15:42:24 +02:00
return crypto . NewAuthenticationWriter ( auth , sizeParser , writer , request . Command . TransferType ( ) , padding )
2020-10-11 19:22:46 +08:00
2018-02-23 12:13:02 +01:00
default :
panic ( "Unknown security type." )
2016-12-07 17:32:40 +01:00
}
2016-02-27 00:05:53 +01:00
}
2020-06-01 16:40:54 +08:00
func ( s * ServerSession ) DrainConnN ( reader io . Reader , n int ) error {
_ , err := io . CopyN ( ioutil . Discard , reader , int64 ( n ) )
return err
}