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"
2017-02-12 07:57:36 -05:00
"sync"
"time"
2016-12-07 11:32:40 -05:00
2021-04-30 07:08:15 -04:00
"github.com/v2fly/v2ray-core/v4/common/drain"
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/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 ( )
2021-04-30 07:08:15 -04:00
drainer , err := drain . NewBehaviorSeedLimitedDrainer ( int64 ( s . userValidator . GetBehaviorSeed ( ) ) , 16 + 38 , 3266 , 64 )
if err != nil {
return nil , newError ( "failed to initialize drainer" ) . Base ( err )
}
2020-06-02 02:47:54 -04:00
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
2021-04-30 07:08:15 -04:00
drainer . AcknowledgeReceive ( int ( buffer . Len ( ) ) )
return drain . WithError ( drainer , reader , e )
2020-06-02 02:47:54 -04:00
}
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 {
2021-04-30 07:08:15 -04:00
drainer . AcknowledgeReceive ( bytesRead )
2020-06-06 05:11:30 -04:00
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." ) )
}
2021-04-05 13:55:44 -04:00
if s . userValidator . ShouldShowLegacyWarn ( ) {
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. This message will not be shown for further violation on this inbound." ) . 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
}
2021-04-30 07:08:15 -04:00
drainer . AcknowledgeReceive ( 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
}
2021-04-28 18:29:42 -04:00
if request . Option . Has ( protocol . RequestOptionAuthenticatedLength ) {
AuthenticatedLengthKey := vmessaead . KDF16 ( s . requestBodyKey [ : ] , "auth_len" )
AuthenticatedLengthKeyAEAD := crypto . NewAesGcm ( AuthenticatedLengthKey )
lengthAuth := & crypto . AEADAuthenticator {
AEAD : AuthenticatedLengthKeyAEAD ,
NonceGenerator : GenerateChunkNonce ( s . requestBodyIV [ : ] , uint32 ( aead . NonceSize ( ) ) ) ,
AdditionalDataGenerator : crypto . GenerateEmptyBytes ( ) ,
}
sizeParser = NewAEADSizeParser ( lengthAuth )
}
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
}
2021-04-28 18:29:42 -04:00
if request . Option . Has ( protocol . RequestOptionAuthenticatedLength ) {
AuthenticatedLengthKey := vmessaead . KDF16 ( s . requestBodyKey [ : ] , "auth_len" )
AuthenticatedLengthKeyAEAD , err := chacha20poly1305 . New ( GenerateChacha20Poly1305Key ( AuthenticatedLengthKey ) )
common . Must ( err )
lengthAuth := & crypto . AEADAuthenticator {
AEAD : AuthenticatedLengthKeyAEAD ,
NonceGenerator : GenerateChunkNonce ( s . requestBodyIV [ : ] , uint32 ( aead . NonceSize ( ) ) ) ,
AdditionalDataGenerator : crypto . GenerateEmptyBytes ( ) ,
}
sizeParser = NewAEADSizeParser ( lengthAuth )
}
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
}
2021-04-28 18:29:42 -04:00
if request . Option . Has ( protocol . RequestOptionAuthenticatedLength ) {
AuthenticatedLengthKey := vmessaead . KDF16 ( s . requestBodyKey [ : ] , "auth_len" )
AuthenticatedLengthKeyAEAD := crypto . NewAesGcm ( AuthenticatedLengthKey )
lengthAuth := & crypto . AEADAuthenticator {
AEAD : AuthenticatedLengthKeyAEAD ,
NonceGenerator : GenerateChunkNonce ( s . requestBodyIV [ : ] , uint32 ( aead . NonceSize ( ) ) ) ,
AdditionalDataGenerator : crypto . GenerateEmptyBytes ( ) ,
}
sizeParser = NewAEADSizeParser ( lengthAuth )
}
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
}
2021-04-28 18:29:42 -04:00
if request . Option . Has ( protocol . RequestOptionAuthenticatedLength ) {
AuthenticatedLengthKey := vmessaead . KDF16 ( s . requestBodyKey [ : ] , "auth_len" )
AuthenticatedLengthKeyAEAD , err := chacha20poly1305 . New ( GenerateChacha20Poly1305Key ( AuthenticatedLengthKey ) )
common . Must ( err )
lengthAuth := & crypto . AEADAuthenticator {
AEAD : AuthenticatedLengthKeyAEAD ,
NonceGenerator : GenerateChunkNonce ( s . requestBodyIV [ : ] , uint32 ( aead . NonceSize ( ) ) ) ,
AdditionalDataGenerator : crypto . GenerateEmptyBytes ( ) ,
}
sizeParser = NewAEADSizeParser ( lengthAuth )
}
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
}