github.com/chwjbn/xclash@v0.2.0/transport/ssr/protocol/base.go (about)

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