github.com/yaling888/clash@v1.53.0/transport/ssr/protocol/base.go (about)

     1  package protocol
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/aes"
     6  	"crypto/cipher"
     7  	R "crypto/rand"
     8  	"encoding/base64"
     9  	"encoding/binary"
    10  	"math/rand/v2"
    11  	"sync"
    12  	"time"
    13  
    14  	"github.com/phuslu/log"
    15  
    16  	"github.com/yaling888/clash/common/pool"
    17  	"github.com/yaling888/clash/transport/shadowsocks/core"
    18  )
    19  
    20  type Base struct {
    21  	Key      []byte
    22  	Overhead int
    23  	Param    string
    24  }
    25  
    26  type userData struct {
    27  	userKey []byte
    28  	userID  [4]byte
    29  }
    30  
    31  type authData struct {
    32  	clientID     [4]byte
    33  	connectionID uint32
    34  	mutex        sync.Mutex
    35  }
    36  
    37  func (a *authData) next() *authData {
    38  	r := &authData{}
    39  	a.mutex.Lock()
    40  	defer a.mutex.Unlock()
    41  	if a.connectionID > 0xff000000 || a.connectionID == 0 {
    42  		_, _ = R.Read(a.clientID[:])
    43  		a.connectionID = rand.Uint32() & 0xffffff
    44  	}
    45  	a.connectionID++
    46  	copy(r.clientID[:], a.clientID[:])
    47  	r.connectionID = a.connectionID
    48  	return r
    49  }
    50  
    51  func (a *authData) putAuthData(buf *bytes.Buffer) {
    52  	_ = binary.Write(buf, binary.LittleEndian, uint32(time.Now().Unix()))
    53  	buf.Write(a.clientID[:])
    54  	_ = binary.Write(buf, binary.LittleEndian, a.connectionID)
    55  }
    56  
    57  func (a *authData) putEncryptedData(b *bytes.Buffer, userKey []byte, paddings [2]int, salt string) error {
    58  	encrypt := pool.GetBufferWriter()
    59  	encrypt.Grow(16)
    60  	defer pool.PutBufferWriter(encrypt)
    61  
    62  	binary.LittleEndian.PutUint32(*encrypt, uint32(time.Now().Unix()))
    63  	copy((*encrypt)[4:], a.clientID[:])
    64  	binary.LittleEndian.PutUint32((*encrypt)[8:], a.connectionID)
    65  	binary.LittleEndian.PutUint16((*encrypt)[12:], uint16(paddings[0]))
    66  	binary.LittleEndian.PutUint16((*encrypt)[14:], uint16(paddings[1]))
    67  
    68  	cipherKey := core.Kdf(base64.StdEncoding.EncodeToString(userKey)+salt, 16)
    69  	block, err := aes.NewCipher(cipherKey)
    70  	if err != nil {
    71  		log.Warn().Err(err).Msg("[SSR] new cipher failed")
    72  		return err
    73  	}
    74  	iv := bytes.Repeat([]byte{0}, 16)
    75  	cbcCipher := cipher.NewCBCEncrypter(block, iv)
    76  
    77  	cbcCipher.CryptBlocks(*encrypt, encrypt.Bytes())
    78  
    79  	b.Write(encrypt.Bytes())
    80  	return nil
    81  }