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