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 }