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 }