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