github.com/xtls/xray-core@v1.8.12-0.20240518155711-3168d27b0bdb/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/xtls/xray-core/common" 12 "github.com/xtls/xray-core/common/antireplay" 13 "github.com/xtls/xray-core/common/buf" 14 "github.com/xtls/xray-core/common/crypto" 15 "github.com/xtls/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 }