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