github.com/EagleQL/Xray-core@v1.4.3/proxy/shadowsocks/config.go (about)

     1  package shadowsocks
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/aes"
     6  	"crypto/cipher"
     7  	"crypto/md5"
     8  	"crypto/sha1"
     9  	"io"
    10  	"reflect"
    11  	"strconv"
    12  
    13  	"golang.org/x/crypto/chacha20poly1305"
    14  	"golang.org/x/crypto/hkdf"
    15  
    16  	"github.com/xtls/xray-core/common"
    17  	"github.com/xtls/xray-core/common/buf"
    18  	"github.com/xtls/xray-core/common/crypto"
    19  	"github.com/xtls/xray-core/common/protocol"
    20  )
    21  
    22  // MemoryAccount is an account type converted from Account.
    23  type MemoryAccount struct {
    24  	Cipher Cipher
    25  	Key    []byte
    26  }
    27  
    28  // Equals implements protocol.Account.Equals().
    29  func (a *MemoryAccount) Equals(another protocol.Account) bool {
    30  	if account, ok := another.(*MemoryAccount); ok {
    31  		return bytes.Equal(a.Key, account.Key)
    32  	}
    33  	return false
    34  }
    35  
    36  func (a *MemoryAccount) GetCipherName() string {
    37  	switch a.Cipher.(type) {
    38  	case *AesCfb:
    39  		keyBytes := a.Cipher.(*AesCfb).KeyBytes
    40  		return "AES_" + strconv.FormatInt(int64(keyBytes*8), 10) + "_CFB"
    41  	case *ChaCha20:
    42  		if a.Cipher.(*ChaCha20).IVBytes == 8 {
    43  			return "CHACHA20"
    44  		}
    45  		return "CHACHA20_IETF"
    46  	case *AEADCipher:
    47  		switch reflect.ValueOf(a.Cipher.(*AEADCipher).AEADAuthCreator).Pointer() {
    48  		case reflect.ValueOf(createAesGcm).Pointer():
    49  			keyBytes := a.Cipher.(*AEADCipher).KeyBytes
    50  			return "AES_" + strconv.FormatInt(int64(keyBytes*8), 10) + "_GCM"
    51  		case reflect.ValueOf(createChacha20Poly1305).Pointer():
    52  			return "CHACHA20_POLY1305"
    53  		}
    54  	case *NoneCipher:
    55  		return "NONE"
    56  	}
    57  
    58  	return ""
    59  }
    60  
    61  func createAesGcm(key []byte) cipher.AEAD {
    62  	block, err := aes.NewCipher(key)
    63  	common.Must(err)
    64  	gcm, err := cipher.NewGCM(block)
    65  	common.Must(err)
    66  	return gcm
    67  }
    68  
    69  func createChacha20Poly1305(key []byte) cipher.AEAD {
    70  	chacha20, err := chacha20poly1305.New(key)
    71  	common.Must(err)
    72  	return chacha20
    73  }
    74  
    75  func (a *Account) getCipher() (Cipher, error) {
    76  	switch a.CipherType {
    77  	case CipherType_AES_128_CFB:
    78  		return &AesCfb{KeyBytes: 16}, nil
    79  	case CipherType_AES_256_CFB:
    80  		return &AesCfb{KeyBytes: 32}, nil
    81  	case CipherType_CHACHA20:
    82  		return &ChaCha20{IVBytes: 8}, nil
    83  	case CipherType_CHACHA20_IETF:
    84  		return &ChaCha20{IVBytes: 12}, nil
    85  	case CipherType_AES_128_GCM:
    86  		return &AEADCipher{
    87  			KeyBytes:        16,
    88  			IVBytes:         16,
    89  			AEADAuthCreator: createAesGcm,
    90  		}, nil
    91  	case CipherType_AES_256_GCM:
    92  		return &AEADCipher{
    93  			KeyBytes:        32,
    94  			IVBytes:         32,
    95  			AEADAuthCreator: createAesGcm,
    96  		}, nil
    97  	case CipherType_CHACHA20_POLY1305:
    98  		return &AEADCipher{
    99  			KeyBytes:        32,
   100  			IVBytes:         32,
   101  			AEADAuthCreator: createChacha20Poly1305,
   102  		}, nil
   103  	case CipherType_NONE:
   104  		return NoneCipher{}, nil
   105  	default:
   106  		return nil, newError("Unsupported cipher.")
   107  	}
   108  }
   109  
   110  // AsAccount implements protocol.AsAccount.
   111  func (a *Account) AsAccount() (protocol.Account, error) {
   112  	cipher, err := a.getCipher()
   113  	if err != nil {
   114  		return nil, newError("failed to get cipher").Base(err)
   115  	}
   116  	return &MemoryAccount{
   117  		Cipher: cipher,
   118  		Key:    passwordToCipherKey([]byte(a.Password), cipher.KeySize()),
   119  	}, nil
   120  }
   121  
   122  // Cipher is an interface for all Shadowsocks ciphers.
   123  type Cipher interface {
   124  	KeySize() int32
   125  	IVSize() int32
   126  	NewEncryptionWriter(key []byte, iv []byte, writer io.Writer) (buf.Writer, error)
   127  	NewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error)
   128  	IsAEAD() bool
   129  	EncodePacket(key []byte, b *buf.Buffer) error
   130  	DecodePacket(key []byte, b *buf.Buffer) error
   131  }
   132  
   133  // AesCfb represents all AES-CFB ciphers.
   134  type AesCfb struct {
   135  	KeyBytes int32
   136  }
   137  
   138  func (*AesCfb) IsAEAD() bool {
   139  	return false
   140  }
   141  
   142  func (v *AesCfb) KeySize() int32 {
   143  	return v.KeyBytes
   144  }
   145  
   146  func (v *AesCfb) IVSize() int32 {
   147  	return 16
   148  }
   149  
   150  func (v *AesCfb) NewEncryptionWriter(key []byte, iv []byte, writer io.Writer) (buf.Writer, error) {
   151  	stream := crypto.NewAesEncryptionStream(key, iv)
   152  	return &buf.SequentialWriter{Writer: crypto.NewCryptionWriter(stream, writer)}, nil
   153  }
   154  
   155  func (v *AesCfb) NewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error) {
   156  	stream := crypto.NewAesDecryptionStream(key, iv)
   157  	return &buf.SingleReader{
   158  		Reader: crypto.NewCryptionReader(stream, reader),
   159  	}, nil
   160  }
   161  
   162  func (v *AesCfb) EncodePacket(key []byte, b *buf.Buffer) error {
   163  	iv := b.BytesTo(v.IVSize())
   164  	stream := crypto.NewAesEncryptionStream(key, iv)
   165  	stream.XORKeyStream(b.BytesFrom(v.IVSize()), b.BytesFrom(v.IVSize()))
   166  	return nil
   167  }
   168  
   169  func (v *AesCfb) DecodePacket(key []byte, b *buf.Buffer) error {
   170  	if b.Len() <= v.IVSize() {
   171  		return newError("insufficient data: ", b.Len())
   172  	}
   173  	iv := b.BytesTo(v.IVSize())
   174  	stream := crypto.NewAesDecryptionStream(key, iv)
   175  	stream.XORKeyStream(b.BytesFrom(v.IVSize()), b.BytesFrom(v.IVSize()))
   176  	b.Advance(v.IVSize())
   177  	return nil
   178  }
   179  
   180  type AEADCipher struct {
   181  	KeyBytes        int32
   182  	IVBytes         int32
   183  	AEADAuthCreator func(key []byte) cipher.AEAD
   184  }
   185  
   186  func (*AEADCipher) IsAEAD() bool {
   187  	return true
   188  }
   189  
   190  func (c *AEADCipher) KeySize() int32 {
   191  	return c.KeyBytes
   192  }
   193  
   194  func (c *AEADCipher) IVSize() int32 {
   195  	return c.IVBytes
   196  }
   197  
   198  func (c *AEADCipher) createAuthenticator(key []byte, iv []byte) *crypto.AEADAuthenticator {
   199  	nonce := crypto.GenerateInitialAEADNonce()
   200  	subkey := make([]byte, c.KeyBytes)
   201  	hkdfSHA1(key, iv, subkey)
   202  	return &crypto.AEADAuthenticator{
   203  		AEAD:           c.AEADAuthCreator(subkey),
   204  		NonceGenerator: nonce,
   205  	}
   206  }
   207  
   208  func (c *AEADCipher) NewEncryptionWriter(key []byte, iv []byte, writer io.Writer) (buf.Writer, error) {
   209  	auth := c.createAuthenticator(key, iv)
   210  	return crypto.NewAuthenticationWriter(auth, &crypto.AEADChunkSizeParser{
   211  		Auth: auth,
   212  	}, writer, protocol.TransferTypeStream, nil), nil
   213  }
   214  
   215  func (c *AEADCipher) NewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error) {
   216  	auth := c.createAuthenticator(key, iv)
   217  	return crypto.NewAuthenticationReader(auth, &crypto.AEADChunkSizeParser{
   218  		Auth: auth,
   219  	}, reader, protocol.TransferTypeStream, nil), nil
   220  }
   221  
   222  func (c *AEADCipher) EncodePacket(key []byte, b *buf.Buffer) error {
   223  	ivLen := c.IVSize()
   224  	payloadLen := b.Len()
   225  	auth := c.createAuthenticator(key, b.BytesTo(ivLen))
   226  
   227  	b.Extend(int32(auth.Overhead()))
   228  	_, err := auth.Seal(b.BytesTo(ivLen), b.BytesRange(ivLen, payloadLen))
   229  	return err
   230  }
   231  
   232  func (c *AEADCipher) DecodePacket(key []byte, b *buf.Buffer) error {
   233  	if b.Len() <= c.IVSize() {
   234  		return newError("insufficient data: ", b.Len())
   235  	}
   236  	ivLen := c.IVSize()
   237  	payloadLen := b.Len()
   238  	auth := c.createAuthenticator(key, b.BytesTo(ivLen))
   239  
   240  	bbb, err := auth.Open(b.BytesTo(ivLen), b.BytesRange(ivLen, payloadLen))
   241  	if err != nil {
   242  		return err
   243  	}
   244  	b.Resize(ivLen, int32(len(bbb)))
   245  	return nil
   246  }
   247  
   248  type ChaCha20 struct {
   249  	IVBytes int32
   250  }
   251  
   252  func (*ChaCha20) IsAEAD() bool {
   253  	return false
   254  }
   255  
   256  func (v *ChaCha20) KeySize() int32 {
   257  	return 32
   258  }
   259  
   260  func (v *ChaCha20) IVSize() int32 {
   261  	return v.IVBytes
   262  }
   263  
   264  func (v *ChaCha20) NewEncryptionWriter(key []byte, iv []byte, writer io.Writer) (buf.Writer, error) {
   265  	stream := crypto.NewChaCha20Stream(key, iv)
   266  	return &buf.SequentialWriter{Writer: crypto.NewCryptionWriter(stream, writer)}, nil
   267  }
   268  
   269  func (v *ChaCha20) NewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error) {
   270  	stream := crypto.NewChaCha20Stream(key, iv)
   271  	return &buf.SingleReader{Reader: crypto.NewCryptionReader(stream, reader)}, nil
   272  }
   273  
   274  func (v *ChaCha20) EncodePacket(key []byte, b *buf.Buffer) error {
   275  	iv := b.BytesTo(v.IVSize())
   276  	stream := crypto.NewChaCha20Stream(key, iv)
   277  	stream.XORKeyStream(b.BytesFrom(v.IVSize()), b.BytesFrom(v.IVSize()))
   278  	return nil
   279  }
   280  
   281  func (v *ChaCha20) DecodePacket(key []byte, b *buf.Buffer) error {
   282  	if b.Len() <= v.IVSize() {
   283  		return newError("insufficient data: ", b.Len())
   284  	}
   285  	iv := b.BytesTo(v.IVSize())
   286  	stream := crypto.NewChaCha20Stream(key, iv)
   287  	stream.XORKeyStream(b.BytesFrom(v.IVSize()), b.BytesFrom(v.IVSize()))
   288  	b.Advance(v.IVSize())
   289  	return nil
   290  }
   291  
   292  type NoneCipher struct{}
   293  
   294  func (NoneCipher) KeySize() int32 { return 0 }
   295  func (NoneCipher) IVSize() int32  { return 0 }
   296  func (NoneCipher) IsAEAD() bool {
   297  	return true // to avoid OTA
   298  }
   299  
   300  func (NoneCipher) NewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error) {
   301  	return buf.NewReader(reader), nil
   302  }
   303  
   304  func (NoneCipher) NewEncryptionWriter(key []byte, iv []byte, writer io.Writer) (buf.Writer, error) {
   305  	return buf.NewWriter(writer), nil
   306  }
   307  
   308  func (NoneCipher) EncodePacket(key []byte, b *buf.Buffer) error {
   309  	return nil
   310  }
   311  
   312  func (NoneCipher) DecodePacket(key []byte, b *buf.Buffer) error {
   313  	return nil
   314  }
   315  
   316  func passwordToCipherKey(password []byte, keySize int32) []byte {
   317  	key := make([]byte, 0, keySize)
   318  
   319  	md5Sum := md5.Sum(password)
   320  	key = append(key, md5Sum[:]...)
   321  
   322  	for int32(len(key)) < keySize {
   323  		md5Hash := md5.New()
   324  		common.Must2(md5Hash.Write(md5Sum[:]))
   325  		common.Must2(md5Hash.Write(password))
   326  		md5Hash.Sum(md5Sum[:0])
   327  
   328  		key = append(key, md5Sum[:]...)
   329  	}
   330  	return key
   331  }
   332  
   333  func hkdfSHA1(secret, salt, outkey []byte) {
   334  	r := hkdf.New(sha1.New, secret, salt, []byte("ss-subkey"))
   335  	common.Must2(io.ReadFull(r, outkey))
   336  }