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