github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/proxy/shadowsocks2022/encoding.go (about)

     1  package shadowsocks2022
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/cipher"
     6  	cryptoRand "crypto/rand"
     7  	"encoding/binary"
     8  	"io"
     9  	"time"
    10  
    11  	"github.com/lunixbochs/struc"
    12  
    13  	"github.com/v2fly/v2ray-core/v5/common"
    14  	"github.com/v2fly/v2ray-core/v5/common/buf"
    15  	"github.com/v2fly/v2ray-core/v5/common/crypto"
    16  	"github.com/v2fly/v2ray-core/v5/common/dice"
    17  	"github.com/v2fly/v2ray-core/v5/common/net"
    18  	"github.com/v2fly/v2ray-core/v5/common/protocol"
    19  )
    20  
    21  type TCPRequest struct {
    22  	keyDerivation KeyDerivation
    23  	method        Method
    24  
    25  	c2sSalt  RequestSalt
    26  	c2sNonce crypto.BytesGenerator
    27  	c2sAEAD  cipher.AEAD
    28  
    29  	s2cSalt  RequestSalt
    30  	s2cNonce crypto.BytesGenerator
    31  	s2cAEAD  cipher.AEAD
    32  
    33  	s2cSaltAssert         RequestSalt
    34  	s2cInitialPayloadSize int
    35  }
    36  
    37  func (t *TCPRequest) EncodeTCPRequestHeader(effectivePsk []byte,
    38  	eih [][]byte, address DestinationAddress, destPort int, initialPayload []byte, out *buf.Buffer,
    39  ) error {
    40  	requestSalt := newRequestSaltWithLength(t.method.GetSessionSubKeyAndSaltLength())
    41  	{
    42  		err := requestSalt.FillAllFrom(cryptoRand.Reader)
    43  		if err != nil {
    44  			return newError("failed to fill salt").Base(err)
    45  		}
    46  	}
    47  	t.c2sSalt = requestSalt
    48  	sessionKey := make([]byte, t.method.GetSessionSubKeyAndSaltLength())
    49  	{
    50  		err := t.keyDerivation.GetSessionSubKey(effectivePsk, requestSalt.Bytes(), sessionKey)
    51  		if err != nil {
    52  			return newError("failed to get session sub key").Base(err)
    53  		}
    54  	}
    55  
    56  	aead, err := t.method.GetStreamAEAD(sessionKey)
    57  	if err != nil {
    58  		return newError("failed to get stream AEAD").Base(err)
    59  	}
    60  	t.c2sAEAD = aead
    61  	paddingLength := TCPMinPaddingLength
    62  	if initialPayload == nil {
    63  		initialPayload = []byte{}
    64  		paddingLength += 1 + dice.RollWith(TCPMaxPaddingLength, cryptoRand.Reader)
    65  	}
    66  
    67  	variableLengthHeader := &TCPRequestHeader3VariableLength{
    68  		DestinationAddress: address,
    69  		Contents: struct {
    70  			PaddingLength uint16 `struc:"sizeof=Padding"`
    71  			Padding       []byte
    72  		}(struct {
    73  			PaddingLength uint16
    74  			Padding       []byte
    75  		}{
    76  			PaddingLength: uint16(paddingLength),
    77  			Padding:       make([]byte, paddingLength),
    78  		}),
    79  	}
    80  	variableLengthHeaderBuffer := buf.New()
    81  	defer variableLengthHeaderBuffer.Release()
    82  	{
    83  		err := addrParser.WriteAddressPort(variableLengthHeaderBuffer, address, net.Port(destPort))
    84  		if err != nil {
    85  			return newError("failed to write address port").Base(err)
    86  		}
    87  	}
    88  	{
    89  		err := struc.Pack(variableLengthHeaderBuffer, &variableLengthHeader.Contents)
    90  		if err != nil {
    91  			return newError("failed to pack variable length header").Base(err)
    92  		}
    93  	}
    94  	{
    95  		_, err := variableLengthHeaderBuffer.Write(initialPayload)
    96  		if err != nil {
    97  			return newError("failed to write initial payload").Base(err)
    98  		}
    99  	}
   100  
   101  	fixedLengthHeader := &TCPRequestHeader2FixedLength{
   102  		Type:         TCPHeaderTypeClientToServerStream,
   103  		Timestamp:    uint64(time.Now().Unix()),
   104  		HeaderLength: uint16(variableLengthHeaderBuffer.Len()),
   105  	}
   106  
   107  	fixedLengthHeaderBuffer := buf.New()
   108  	defer fixedLengthHeaderBuffer.Release()
   109  	{
   110  		err := struc.Pack(fixedLengthHeaderBuffer, fixedLengthHeader)
   111  		if err != nil {
   112  			return newError("failed to pack fixed length header").Base(err)
   113  		}
   114  	}
   115  	eihHeader := ExtensibleIdentityHeaders(newAESEIH(0))
   116  	if len(eih) != 0 {
   117  		eihGenerator := newAESEIHGeneratorContainer(len(eih), effectivePsk, eih)
   118  		eihHeaderGenerated, err := eihGenerator.GenerateEIH(t.keyDerivation, t.method, requestSalt.Bytes())
   119  		if err != nil {
   120  			return newError("failed to construct EIH").Base(err)
   121  		}
   122  		eihHeader = eihHeaderGenerated
   123  	}
   124  	preSessionKeyHeader := &TCPRequestHeader1PreSessionKey{
   125  		Salt: requestSalt,
   126  		EIH:  eihHeader,
   127  	}
   128  	preSessionKeyHeaderBuffer := buf.New()
   129  	defer preSessionKeyHeaderBuffer.Release()
   130  	{
   131  		err := struc.Pack(preSessionKeyHeaderBuffer, preSessionKeyHeader)
   132  		if err != nil {
   133  			return newError("failed to pack pre session key header").Base(err)
   134  		}
   135  	}
   136  	requestNonce := crypto.GenerateInitialAEADNonce()
   137  	t.c2sNonce = requestNonce
   138  	{
   139  		n, err := out.Write(preSessionKeyHeaderBuffer.BytesFrom(0))
   140  		if err != nil {
   141  			return newError("failed to write pre session key header").Base(err)
   142  		}
   143  		if int32(n) != preSessionKeyHeaderBuffer.Len() {
   144  			return newError("failed to write pre session key header")
   145  		}
   146  	}
   147  	{
   148  		fixedLengthEncrypted := out.Extend(fixedLengthHeaderBuffer.Len() + int32(aead.Overhead()))
   149  		aead.Seal(fixedLengthEncrypted[:0], requestNonce(), fixedLengthHeaderBuffer.Bytes(), nil)
   150  	}
   151  	{
   152  		variableLengthEncrypted := out.Extend(variableLengthHeaderBuffer.Len() + int32(aead.Overhead()))
   153  		aead.Seal(variableLengthEncrypted[:0], requestNonce(), variableLengthHeaderBuffer.Bytes(), nil)
   154  	}
   155  	return nil
   156  }
   157  
   158  func (t *TCPRequest) DecodeTCPResponseHeader(effectivePsk []byte, in io.Reader) error {
   159  	var preSessionKeyHeader TCPResponseHeader1PreSessionKey
   160  	preSessionKeyHeader.Salt = newRequestSaltWithLength(t.method.GetSessionSubKeyAndSaltLength())
   161  	{
   162  		err := struc.Unpack(in, &preSessionKeyHeader)
   163  		if err != nil {
   164  			return newError("failed to unpack pre session key header").Base(err)
   165  		}
   166  	}
   167  	s2cSalt := preSessionKeyHeader.Salt.Bytes()
   168  	t.s2cSalt = preSessionKeyHeader.Salt
   169  	sessionKey := make([]byte, t.method.GetSessionSubKeyAndSaltLength())
   170  	{
   171  		err := t.keyDerivation.GetSessionSubKey(effectivePsk, s2cSalt, sessionKey)
   172  		if err != nil {
   173  			return newError("failed to get session sub key").Base(err)
   174  		}
   175  	}
   176  	aead, err := t.method.GetStreamAEAD(sessionKey)
   177  	if err != nil {
   178  		return newError("failed to get stream AEAD").Base(err)
   179  	}
   180  	t.s2cAEAD = aead
   181  
   182  	fixedLengthHeaderEncryptedBuffer := buf.New()
   183  	defer fixedLengthHeaderEncryptedBuffer.Release()
   184  	{
   185  		_, err := fixedLengthHeaderEncryptedBuffer.ReadFullFrom(in, 11+int32(t.method.GetSessionSubKeyAndSaltLength())+int32(aead.Overhead()))
   186  		if err != nil {
   187  			return newError("failed to read fixed length header encrypted").Base(err)
   188  		}
   189  	}
   190  	s2cNonce := crypto.GenerateInitialAEADNonce()
   191  	t.s2cNonce = s2cNonce
   192  	fixedLengthHeaderDecryptedBuffer := buf.New()
   193  	defer fixedLengthHeaderDecryptedBuffer.Release()
   194  	{
   195  		decryptionBuffer := fixedLengthHeaderDecryptedBuffer.Extend(11 + int32(t.method.GetSessionSubKeyAndSaltLength()))
   196  		_, err = aead.Open(decryptionBuffer[:0], s2cNonce(), fixedLengthHeaderEncryptedBuffer.Bytes(), nil)
   197  		if err != nil {
   198  			return newError("failed to decrypt fixed length header").Base(err)
   199  		}
   200  	}
   201  	var fixedLengthHeader TCPResponseHeader2FixedLength
   202  	fixedLengthHeader.RequestSalt = newRequestSaltWithLength(t.method.GetSessionSubKeyAndSaltLength())
   203  	{
   204  		err := struc.Unpack(bytes.NewReader(fixedLengthHeaderDecryptedBuffer.Bytes()), &fixedLengthHeader)
   205  		if err != nil {
   206  			return newError("failed to unpack fixed length header").Base(err)
   207  		}
   208  	}
   209  
   210  	if fixedLengthHeader.Type != TCPHeaderTypeServerToClientStream {
   211  		return newError("unexpected TCP header type")
   212  	}
   213  	timeDifference := int64(fixedLengthHeader.Timestamp) - time.Now().Unix()
   214  	if timeDifference < -30 || timeDifference > 30 {
   215  		return newError("timestamp is too far away, timeDifference = ", timeDifference)
   216  	}
   217  
   218  	t.s2cSaltAssert = fixedLengthHeader.RequestSalt
   219  	t.s2cInitialPayloadSize = int(fixedLengthHeader.InitialPayloadLength)
   220  	return nil
   221  }
   222  
   223  func (t *TCPRequest) CheckC2SConnectionConstraint() error {
   224  	if !bytes.Equal(t.c2sSalt.Bytes(), t.s2cSaltAssert.Bytes()) {
   225  		return newError("c2s salt not equal to s2c salt assert")
   226  	}
   227  	return nil
   228  }
   229  
   230  func (t *TCPRequest) CreateClientS2CReader(in io.Reader, initialPayload *buf.Buffer) (buf.Reader, error) {
   231  	AEADAuthenticator := &crypto.AEADAuthenticator{
   232  		AEAD:                    t.s2cAEAD,
   233  		NonceGenerator:          t.s2cNonce,
   234  		AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
   235  	}
   236  	initialPayloadEncrypted := buf.NewWithSize(65535)
   237  	defer initialPayloadEncrypted.Release()
   238  	initialPayloadEncryptedBytes := initialPayloadEncrypted.Extend(int32(t.s2cAEAD.Overhead()) + int32(t.s2cInitialPayloadSize))
   239  	_, err := io.ReadFull(in, initialPayloadEncryptedBytes)
   240  	if err != nil {
   241  		return nil, newError("failed to read initial payload").Base(err)
   242  	}
   243  	initialPayloadBytes := initialPayload.Extend(int32(t.s2cInitialPayloadSize))
   244  	_, err = t.s2cAEAD.Open(initialPayloadBytes[:0], t.s2cNonce(), initialPayloadEncryptedBytes, nil)
   245  	if err != nil {
   246  		return nil, newError("failed to decrypt initial payload").Base(err)
   247  	}
   248  	return crypto.NewAuthenticationReader(AEADAuthenticator, &AEADChunkSizeParser{
   249  		Auth: AEADAuthenticator,
   250  	}, in, protocol.TransferTypeStream, nil), nil
   251  }
   252  
   253  func (t *TCPRequest) CreateClientC2SWriter(writer io.Writer) buf.Writer {
   254  	AEADAuthenticator := &crypto.AEADAuthenticator{
   255  		AEAD:                    t.c2sAEAD,
   256  		NonceGenerator:          t.c2sNonce,
   257  		AdditionalDataGenerator: crypto.GenerateEmptyBytes(),
   258  	}
   259  	sizeParser := &crypto.AEADChunkSizeParser{
   260  		Auth: AEADAuthenticator,
   261  	}
   262  	return crypto.NewAuthenticationWriter(AEADAuthenticator, sizeParser, writer, protocol.TransferTypeStream, nil)
   263  }
   264  
   265  type AEADChunkSizeParser struct {
   266  	Auth *crypto.AEADAuthenticator
   267  }
   268  
   269  func (p *AEADChunkSizeParser) HasConstantOffset() uint16 {
   270  	return uint16(p.Auth.Overhead())
   271  }
   272  
   273  func (p *AEADChunkSizeParser) SizeBytes() int32 {
   274  	return 2 + int32(p.Auth.Overhead())
   275  }
   276  
   277  func (p *AEADChunkSizeParser) Encode(size uint16, b []byte) []byte {
   278  	binary.BigEndian.PutUint16(b, size-uint16(p.Auth.Overhead()))
   279  	b, err := p.Auth.Seal(b[:0], b[:2])
   280  	common.Must(err)
   281  	return b
   282  }
   283  
   284  func (p *AEADChunkSizeParser) Decode(b []byte) (uint16, error) {
   285  	b, err := p.Auth.Open(b[:0], b)
   286  	if err != nil {
   287  		return 0, err
   288  	}
   289  	return binary.BigEndian.Uint16(b), nil
   290  }