github.com/xraypb/xray-core@v1.6.6/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  
    11  	"github.com/xraypb/xray-core/common"
    12  	"github.com/xraypb/xray-core/common/antireplay"
    13  	"github.com/xraypb/xray-core/common/buf"
    14  	"github.com/xraypb/xray-core/common/crypto"
    15  	"github.com/xraypb/xray-core/common/protocol"
    16  	"golang.org/x/crypto/chacha20poly1305"
    17  	"golang.org/x/crypto/hkdf"
    18  )
    19  
    20  // MemoryAccount is an account type converted from Account.
    21  type MemoryAccount struct {
    22  	Cipher Cipher
    23  	Key    []byte
    24  
    25  	replayFilter antireplay.GeneralizedReplayFilter
    26  }
    27  
    28  var ErrIVNotUnique = newError("IV is not unique")
    29  
    30  // Equals implements protocol.Account.Equals().
    31  func (a *MemoryAccount) Equals(another protocol.Account) bool {
    32  	if account, ok := another.(*MemoryAccount); ok {
    33  		return bytes.Equal(a.Key, account.Key)
    34  	}
    35  	return false
    36  }
    37  
    38  func (a *MemoryAccount) CheckIV(iv []byte) error {
    39  	if a.replayFilter == nil {
    40  		return nil
    41  	}
    42  	if a.replayFilter.Check(iv) {
    43  		return nil
    44  	}
    45  	return ErrIVNotUnique
    46  }
    47  
    48  func createAesGcm(key []byte) cipher.AEAD {
    49  	block, err := aes.NewCipher(key)
    50  	common.Must(err)
    51  	gcm, err := cipher.NewGCM(block)
    52  	common.Must(err)
    53  	return gcm
    54  }
    55  
    56  func createChaCha20Poly1305(key []byte) cipher.AEAD {
    57  	ChaChaPoly1305, err := chacha20poly1305.New(key)
    58  	common.Must(err)
    59  	return ChaChaPoly1305
    60  }
    61  
    62  func createXChaCha20Poly1305(key []byte) cipher.AEAD {
    63  	XChaChaPoly1305, err := chacha20poly1305.NewX(key)
    64  	common.Must(err)
    65  	return XChaChaPoly1305
    66  }
    67  
    68  func (a *Account) getCipher() (Cipher, error) {
    69  	switch a.CipherType {
    70  	case CipherType_AES_128_GCM:
    71  		return &AEADCipher{
    72  			KeyBytes:        16,
    73  			IVBytes:         16,
    74  			AEADAuthCreator: createAesGcm,
    75  		}, nil
    76  	case CipherType_AES_256_GCM:
    77  		return &AEADCipher{
    78  			KeyBytes:        32,
    79  			IVBytes:         32,
    80  			AEADAuthCreator: createAesGcm,
    81  		}, nil
    82  	case CipherType_CHACHA20_POLY1305:
    83  		return &AEADCipher{
    84  			KeyBytes:        32,
    85  			IVBytes:         32,
    86  			AEADAuthCreator: createChaCha20Poly1305,
    87  		}, nil
    88  	case CipherType_XCHACHA20_POLY1305:
    89  		return &AEADCipher{
    90  			KeyBytes:        32,
    91  			IVBytes:         32,
    92  			AEADAuthCreator: createXChaCha20Poly1305,
    93  		}, nil
    94  	case CipherType_NONE:
    95  		return NoneCipher{}, nil
    96  	default:
    97  		return nil, newError("Unsupported cipher.")
    98  	}
    99  }
   100  
   101  // AsAccount implements protocol.AsAccount.
   102  func (a *Account) AsAccount() (protocol.Account, error) {
   103  	Cipher, err := a.getCipher()
   104  	if err != nil {
   105  		return nil, newError("failed to get cipher").Base(err)
   106  	}
   107  	return &MemoryAccount{
   108  		Cipher: Cipher,
   109  		Key:    passwordToCipherKey([]byte(a.Password), Cipher.KeySize()),
   110  		replayFilter: func() antireplay.GeneralizedReplayFilter {
   111  			if a.IvCheck {
   112  				return antireplay.NewBloomRing()
   113  			}
   114  			return nil
   115  		}(),
   116  	}, nil
   117  }
   118  
   119  // Cipher is an interface for all Shadowsocks ciphers.
   120  type Cipher interface {
   121  	KeySize() int32
   122  	IVSize() int32
   123  	NewEncryptionWriter(key []byte, iv []byte, writer io.Writer) (buf.Writer, error)
   124  	NewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error)
   125  	IsAEAD() bool
   126  	EncodePacket(key []byte, b *buf.Buffer) error
   127  	DecodePacket(key []byte, b *buf.Buffer) error
   128  }
   129  
   130  type AEADCipher struct {
   131  	KeyBytes        int32
   132  	IVBytes         int32
   133  	AEADAuthCreator func(key []byte) cipher.AEAD
   134  }
   135  
   136  func (*AEADCipher) IsAEAD() bool {
   137  	return true
   138  }
   139  
   140  func (c *AEADCipher) KeySize() int32 {
   141  	return c.KeyBytes
   142  }
   143  
   144  func (c *AEADCipher) IVSize() int32 {
   145  	return c.IVBytes
   146  }
   147  
   148  func (c *AEADCipher) createAuthenticator(key []byte, iv []byte) *crypto.AEADAuthenticator {
   149  	subkey := make([]byte, c.KeyBytes)
   150  	hkdfSHA1(key, iv, subkey)
   151  	aead := c.AEADAuthCreator(subkey)
   152  	nonce := crypto.GenerateAEADNonceWithSize(aead.NonceSize())
   153  	return &crypto.AEADAuthenticator{
   154  		AEAD:           aead,
   155  		NonceGenerator: nonce,
   156  	}
   157  }
   158  
   159  func (c *AEADCipher) NewEncryptionWriter(key []byte, iv []byte, writer io.Writer) (buf.Writer, error) {
   160  	auth := c.createAuthenticator(key, iv)
   161  	return crypto.NewAuthenticationWriter(auth, &crypto.AEADChunkSizeParser{
   162  		Auth: auth,
   163  	}, writer, protocol.TransferTypeStream, nil), nil
   164  }
   165  
   166  func (c *AEADCipher) NewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error) {
   167  	auth := c.createAuthenticator(key, iv)
   168  	return crypto.NewAuthenticationReader(auth, &crypto.AEADChunkSizeParser{
   169  		Auth: auth,
   170  	}, reader, protocol.TransferTypeStream, nil), nil
   171  }
   172  
   173  func (c *AEADCipher) EncodePacket(key []byte, b *buf.Buffer) error {
   174  	ivLen := c.IVSize()
   175  	payloadLen := b.Len()
   176  	auth := c.createAuthenticator(key, b.BytesTo(ivLen))
   177  
   178  	b.Extend(int32(auth.Overhead()))
   179  	_, err := auth.Seal(b.BytesTo(ivLen), b.BytesRange(ivLen, payloadLen))
   180  	return err
   181  }
   182  
   183  func (c *AEADCipher) DecodePacket(key []byte, b *buf.Buffer) error {
   184  	if b.Len() <= c.IVSize() {
   185  		return newError("insufficient data: ", b.Len())
   186  	}
   187  	ivLen := c.IVSize()
   188  	payloadLen := b.Len()
   189  	auth := c.createAuthenticator(key, b.BytesTo(ivLen))
   190  
   191  	bbb, err := auth.Open(b.BytesTo(ivLen), b.BytesRange(ivLen, payloadLen))
   192  	if err != nil {
   193  		return err
   194  	}
   195  	b.Resize(ivLen, int32(len(bbb)))
   196  	return nil
   197  }
   198  
   199  type NoneCipher struct{}
   200  
   201  func (NoneCipher) KeySize() int32 { return 0 }
   202  func (NoneCipher) IVSize() int32  { return 0 }
   203  func (NoneCipher) IsAEAD() bool {
   204  	return false
   205  }
   206  
   207  func (NoneCipher) NewDecryptionReader(key []byte, iv []byte, reader io.Reader) (buf.Reader, error) {
   208  	return buf.NewReader(reader), nil
   209  }
   210  
   211  func (NoneCipher) NewEncryptionWriter(key []byte, iv []byte, writer io.Writer) (buf.Writer, error) {
   212  	return buf.NewWriter(writer), nil
   213  }
   214  
   215  func (NoneCipher) EncodePacket(key []byte, b *buf.Buffer) error {
   216  	return nil
   217  }
   218  
   219  func (NoneCipher) DecodePacket(key []byte, b *buf.Buffer) error {
   220  	return nil
   221  }
   222  
   223  func passwordToCipherKey(password []byte, keySize int32) []byte {
   224  	key := make([]byte, 0, keySize)
   225  
   226  	md5Sum := md5.Sum(password)
   227  	key = append(key, md5Sum[:]...)
   228  
   229  	for int32(len(key)) < keySize {
   230  		md5Hash := md5.New()
   231  		common.Must2(md5Hash.Write(md5Sum[:]))
   232  		common.Must2(md5Hash.Write(password))
   233  		md5Hash.Sum(md5Sum[:0])
   234  
   235  		key = append(key, md5Sum[:]...)
   236  	}
   237  	return key
   238  }
   239  
   240  func hkdfSHA1(secret, salt, outKey []byte) {
   241  	r := hkdf.New(sha1.New, secret, salt, []byte("ss-subkey"))
   242  	common.Must2(io.ReadFull(r, outKey))
   243  }