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