Skip to content

Commit 82ea7a3

Browse files
authored
VLESS Encryption: Re-add automatically ChaCha20-Poly1305
#5067 (comment) Fixes #4952 (comment) for cheap routers
1 parent 56a45ad commit 82ea7a3

File tree

3 files changed

+67
-54
lines changed

3 files changed

+67
-54
lines changed

proxy/vless/encryption/client.go

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212

1313
"github.com/xtls/xray-core/common/crypto"
1414
"github.com/xtls/xray-core/common/errors"
15+
"github.com/xtls/xray-core/common/protocol"
1516
"lukechampine.com/blake3"
1617
)
1718

@@ -66,7 +67,7 @@ func (i *ClientInstance) Handshake(conn net.Conn) (*CommonConn, error) {
6667
if i.NfsPKeys == nil {
6768
return nil, errors.New("uninitialized")
6869
}
69-
c := NewCommonConn(conn)
70+
c := NewCommonConn(conn, protocol.HasAESGCMHardwareSupport)
7071

7172
ivAndRealysLength := 16 + i.RelaysLength
7273
pfsKeyExchangeLength := 18 + 1184 + 32 + 16
@@ -108,18 +109,18 @@ func (i *ClientInstance) Handshake(conn net.Conn) (*CommonConn, error) {
108109
lastCTR.XORKeyStream(relays[index:], i.Hash32s[j+1][:])
109110
relays = relays[index+32:]
110111
}
111-
nfsGCM := NewGCM(iv, nfsKey)
112+
nfsAEAD := NewAEAD(iv, nfsKey, c.UseAES)
112113

113114
if i.Seconds > 0 {
114115
i.RWLock.RLock()
115116
if time.Now().Before(i.Expire) {
116117
c.Client = i
117118
c.UnitedKey = append(i.PfsKey, nfsKey...) // different unitedKey for each connection
118-
nfsGCM.Seal(clientHello[:ivAndRealysLength], nil, EncodeLength(32), nil)
119-
nfsGCM.Seal(clientHello[:ivAndRealysLength+18], nil, i.Ticket, nil)
119+
nfsAEAD.Seal(clientHello[:ivAndRealysLength], nil, EncodeLength(32), nil)
120+
nfsAEAD.Seal(clientHello[:ivAndRealysLength+18], nil, i.Ticket, nil)
120121
i.RWLock.RUnlock()
121122
c.PreWrite = clientHello[:ivAndRealysLength+18+32]
122-
c.GCM = NewGCM(clientHello[ivAndRealysLength+18:ivAndRealysLength+18+32], c.UnitedKey)
123+
c.AEAD = NewAEAD(clientHello[ivAndRealysLength+18:ivAndRealysLength+18+32], c.UnitedKey, c.UseAES)
123124
if i.XorMode == 2 {
124125
c.Conn = NewXorConn(conn, NewCTR(c.UnitedKey, iv), nil, len(c.PreWrite), 16)
125126
}
@@ -129,15 +130,15 @@ func (i *ClientInstance) Handshake(conn net.Conn) (*CommonConn, error) {
129130
}
130131

131132
pfsKeyExchange := clientHello[ivAndRealysLength : ivAndRealysLength+pfsKeyExchangeLength]
132-
nfsGCM.Seal(pfsKeyExchange[:0], nil, EncodeLength(pfsKeyExchangeLength-18), nil)
133+
nfsAEAD.Seal(pfsKeyExchange[:0], nil, EncodeLength(pfsKeyExchangeLength-18), nil)
133134
mlkem768DKey, _ := mlkem.GenerateKey768()
134135
x25519SKey, _ := ecdh.X25519().GenerateKey(rand.Reader)
135136
pfsPublicKey := append(mlkem768DKey.EncapsulationKey().Bytes(), x25519SKey.PublicKey().Bytes()...)
136-
nfsGCM.Seal(pfsKeyExchange[:18], nil, pfsPublicKey, nil)
137+
nfsAEAD.Seal(pfsKeyExchange[:18], nil, pfsPublicKey, nil)
137138

138139
padding := clientHello[ivAndRealysLength+pfsKeyExchangeLength:]
139-
nfsGCM.Seal(padding[:0], nil, EncodeLength(paddingLength-18), nil)
140-
nfsGCM.Seal(padding[:18], nil, padding[18:paddingLength-16], nil)
140+
nfsAEAD.Seal(padding[:0], nil, EncodeLength(paddingLength-18), nil)
141+
nfsAEAD.Seal(padding[:18], nil, padding[18:paddingLength-16], nil)
141142

142143
if _, err := conn.Write(clientHello); err != nil {
143144
return nil, err
@@ -148,7 +149,7 @@ func (i *ClientInstance) Handshake(conn net.Conn) (*CommonConn, error) {
148149
if _, err := io.ReadFull(conn, encryptedPfsPublicKey); err != nil {
149150
return nil, err
150151
}
151-
nfsGCM.Open(encryptedPfsPublicKey[:0], MaxNonce, encryptedPfsPublicKey, nil)
152+
nfsAEAD.Open(encryptedPfsPublicKey[:0], MaxNonce, encryptedPfsPublicKey, nil)
152153
mlkem768Key, err := mlkem768DKey.Decapsulate(encryptedPfsPublicKey[:1088])
153154
if err != nil {
154155
return nil, err
@@ -165,14 +166,14 @@ func (i *ClientInstance) Handshake(conn net.Conn) (*CommonConn, error) {
165166
copy(pfsKey, mlkem768Key)
166167
copy(pfsKey[32:], x25519Key)
167168
c.UnitedKey = append(pfsKey, nfsKey...)
168-
c.GCM = NewGCM(pfsPublicKey, c.UnitedKey)
169-
c.PeerGCM = NewGCM(encryptedPfsPublicKey[:1088+32], c.UnitedKey)
169+
c.AEAD = NewAEAD(pfsPublicKey, c.UnitedKey, c.UseAES)
170+
c.PeerAEAD = NewAEAD(encryptedPfsPublicKey[:1088+32], c.UnitedKey, c.UseAES)
170171

171172
encryptedTicket := make([]byte, 32)
172173
if _, err := io.ReadFull(conn, encryptedTicket); err != nil {
173174
return nil, err
174175
}
175-
if _, err := c.PeerGCM.Open(encryptedTicket[:0], nil, encryptedTicket, nil); err != nil {
176+
if _, err := c.PeerAEAD.Open(encryptedTicket[:0], nil, encryptedTicket, nil); err != nil {
176177
return nil, err
177178
}
178179
seconds := DecodeLength(encryptedTicket)
@@ -189,7 +190,7 @@ func (i *ClientInstance) Handshake(conn net.Conn) (*CommonConn, error) {
189190
if _, err := io.ReadFull(conn, encryptedLength); err != nil {
190191
return nil, err
191192
}
192-
if _, err := c.PeerGCM.Open(encryptedLength[:0], nil, encryptedLength, nil); err != nil {
193+
if _, err := c.PeerAEAD.Open(encryptedLength[:0], nil, encryptedLength, nil); err != nil {
193194
return nil, err
194195
}
195196
length := DecodeLength(encryptedLength[:2])

proxy/vless/encryption/common.go

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"time"
1313

1414
"github.com/xtls/xray-core/common/errors"
15+
"golang.org/x/crypto/chacha20poly1305"
1516
"lukechampine.com/blake3"
1617
)
1718

@@ -23,19 +24,21 @@ var OutBytesPool = sync.Pool{
2324

2425
type CommonConn struct {
2526
net.Conn
27+
UseAES bool
2628
Client *ClientInstance
2729
UnitedKey []byte
2830
PreWrite []byte
29-
GCM *GCM
30-
PeerGCM *GCM
31+
AEAD *AEAD
32+
PeerAEAD *AEAD
3133
PeerPadding []byte
3234
PeerInBytes []byte
3335
PeerCache []byte
3436
}
3537

36-
func NewCommonConn(conn net.Conn) *CommonConn {
38+
func NewCommonConn(conn net.Conn, useAES bool) *CommonConn {
3739
return &CommonConn{
3840
Conn: conn,
41+
UseAES: useAES,
3942
PeerInBytes: make([]byte, 5+17000), // no need to use sync.Pool, because we are always reading
4043
}
4144
}
@@ -55,12 +58,12 @@ func (c *CommonConn) Write(b []byte) (int, error) {
5558
headerAndData := outBytes[:5+len(b)+16]
5659
EncodeHeader(headerAndData, len(b)+16)
5760
max := false
58-
if bytes.Equal(c.GCM.Nonce[:], MaxNonce) {
61+
if bytes.Equal(c.AEAD.Nonce[:], MaxNonce) {
5962
max = true
6063
}
61-
c.GCM.Seal(headerAndData[:5], nil, b, headerAndData[:5])
64+
c.AEAD.Seal(headerAndData[:5], nil, b, headerAndData[:5])
6265
if max {
63-
c.GCM = NewGCM(headerAndData, c.UnitedKey)
66+
c.AEAD = NewAEAD(headerAndData, c.UnitedKey, c.UseAES)
6467
}
6568
if c.PreWrite != nil {
6669
headerAndData = append(c.PreWrite, headerAndData...)
@@ -77,12 +80,12 @@ func (c *CommonConn) Read(b []byte) (int, error) {
7780
if len(b) == 0 {
7881
return 0, nil
7982
}
80-
if c.PeerGCM == nil { // client's 0-RTT
83+
if c.PeerAEAD == nil { // client's 0-RTT
8184
serverRandom := make([]byte, 16)
8285
if _, err := io.ReadFull(c.Conn, serverRandom); err != nil {
8386
return 0, err
8487
}
85-
c.PeerGCM = NewGCM(serverRandom, c.UnitedKey)
88+
c.PeerAEAD = NewAEAD(serverRandom, c.UnitedKey, c.UseAES)
8689
if xorConn, ok := c.Conn.(*XorConn); ok {
8790
xorConn.PeerCTR = NewCTR(c.UnitedKey, serverRandom)
8891
}
@@ -91,7 +94,7 @@ func (c *CommonConn) Read(b []byte) (int, error) {
9194
if _, err := io.ReadFull(c.Conn, c.PeerPadding); err != nil {
9295
return 0, err
9396
}
94-
if _, err := c.PeerGCM.Open(c.PeerPadding[:0], nil, c.PeerPadding, nil); err != nil {
97+
if _, err := c.PeerAEAD.Open(c.PeerPadding[:0], nil, c.PeerPadding, nil); err != nil {
9598
return 0, err
9699
}
97100
c.PeerPadding = nil
@@ -126,13 +129,13 @@ func (c *CommonConn) Read(b []byte) (int, error) {
126129
if len(dst) <= len(b) {
127130
dst = b[:len(dst)] // avoids another copy()
128131
}
129-
var newGCM *GCM
130-
if bytes.Equal(c.PeerGCM.Nonce[:], MaxNonce) {
131-
newGCM = NewGCM(c.PeerInBytes[:5+l], c.UnitedKey)
132+
var newAEAD *AEAD
133+
if bytes.Equal(c.PeerAEAD.Nonce[:], MaxNonce) {
134+
newAEAD = NewAEAD(c.PeerInBytes[:5+l], c.UnitedKey, c.UseAES)
132135
}
133-
_, err = c.PeerGCM.Open(dst[:0], nil, peerData, peerHeader)
134-
if newGCM != nil {
135-
c.PeerGCM = newGCM
136+
_, err = c.PeerAEAD.Open(dst[:0], nil, peerData, peerHeader)
137+
if newAEAD != nil {
138+
c.PeerAEAD = newAEAD
136139
}
137140
if err != nil {
138141
return 0, err
@@ -144,28 +147,32 @@ func (c *CommonConn) Read(b []byte) (int, error) {
144147
return len(dst), nil
145148
}
146149

147-
type GCM struct {
150+
type AEAD struct {
148151
cipher.AEAD
149152
Nonce [12]byte
150153
}
151154

152-
func NewGCM(ctx, key []byte) *GCM {
155+
func NewAEAD(ctx, key []byte, useAES bool) *AEAD {
153156
k := make([]byte, 32)
154157
blake3.DeriveKey(k, string(ctx), key)
155-
block, _ := aes.NewCipher(k)
156-
aead, _ := cipher.NewGCM(block)
157-
return &GCM{AEAD: aead}
158-
//chacha20poly1305.New()
158+
var aead cipher.AEAD
159+
if useAES {
160+
block, _ := aes.NewCipher(k)
161+
aead, _ = cipher.NewGCM(block)
162+
} else {
163+
aead, _ = chacha20poly1305.New(k)
164+
}
165+
return &AEAD{AEAD: aead}
159166
}
160167

161-
func (a *GCM) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
168+
func (a *AEAD) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
162169
if nonce == nil {
163170
nonce = IncreaseNonce(a.Nonce[:])
164171
}
165172
return a.AEAD.Seal(dst, nonce, plaintext, additionalData)
166173
}
167174

168-
func (a *GCM) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
175+
func (a *AEAD) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
169176
if nonce == nil {
170177
nonce = IncreaseNonce(a.Nonce[:])
171178
}

proxy/vless/encryption/server.go

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ func (i *ServerInstance) Handshake(conn net.Conn) (*CommonConn, error) {
102102
if i.NfsSKeys == nil {
103103
return nil, errors.New("uninitialized")
104104
}
105-
c := NewCommonConn(conn)
105+
c := NewCommonConn(conn, true)
106106

107107
ivAndRelays := make([]byte, 16+i.RelaysLength)
108108
if _, err := io.ReadFull(conn, ivAndRelays); err != nil {
@@ -151,16 +151,21 @@ func (i *ServerInstance) Handshake(conn net.Conn) (*CommonConn, error) {
151151
}
152152
relays = relays[32:]
153153
}
154-
nfsGCM := NewGCM(iv, nfsKey)
154+
nfsAEAD := NewAEAD(iv, nfsKey, c.UseAES)
155155

156156
encryptedLength := make([]byte, 18)
157157
if _, err := io.ReadFull(conn, encryptedLength); err != nil {
158158
return nil, err
159159
}
160-
if _, err := nfsGCM.Open(encryptedLength[:0], nil, encryptedLength, nil); err != nil {
161-
return nil, err
160+
decryptedLength := make([]byte, 2)
161+
if _, err := nfsAEAD.Open(decryptedLength[:0], nil, encryptedLength, nil); err != nil {
162+
c.UseAES = !c.UseAES
163+
nfsAEAD = NewAEAD(iv, nfsKey, c.UseAES)
164+
if _, err := nfsAEAD.Open(decryptedLength[:0], nil, encryptedLength, nil); err != nil {
165+
return nil, err
166+
}
162167
}
163-
length := DecodeLength(encryptedLength[:2])
168+
length := DecodeLength(decryptedLength)
164169

165170
if length == 32 {
166171
if i.Seconds == 0 {
@@ -170,7 +175,7 @@ func (i *ServerInstance) Handshake(conn net.Conn) (*CommonConn, error) {
170175
if _, err := io.ReadFull(conn, encryptedTicket); err != nil {
171176
return nil, err
172177
}
173-
ticket, err := nfsGCM.Open(nil, nil, encryptedTicket, nil)
178+
ticket, err := nfsAEAD.Open(nil, nil, encryptedTicket, nil)
174179
if err != nil {
175180
return nil, err
176181
}
@@ -193,8 +198,8 @@ func (i *ServerInstance) Handshake(conn net.Conn) (*CommonConn, error) {
193198
c.UnitedKey = append(s.PfsKey, nfsKey...) // the same nfsKey links the upload & download (prevents server -> client's another request)
194199
c.PreWrite = make([]byte, 16)
195200
rand.Read(c.PreWrite) // always trust yourself, not the client (also prevents being parsed as TLS thus causing false interruption for "native" and "xorpub")
196-
c.GCM = NewGCM(c.PreWrite, c.UnitedKey)
197-
c.PeerGCM = NewGCM(encryptedTicket, c.UnitedKey) // unchangeable ctx (prevents server -> server), and different ctx length for upload / download (prevents client -> client)
201+
c.AEAD = NewAEAD(c.PreWrite, c.UnitedKey, c.UseAES)
202+
c.PeerAEAD = NewAEAD(encryptedTicket, c.UnitedKey, c.UseAES) // unchangeable ctx (prevents server -> server), and different ctx length for upload / download (prevents client -> client)
198203
if i.XorMode == 2 {
199204
c.Conn = NewXorConn(conn, NewCTR(c.UnitedKey, c.PreWrite), NewCTR(c.UnitedKey, iv), 16, 0) // it doesn't matter if the attacker sends client's iv back to the client
200205
}
@@ -208,7 +213,7 @@ func (i *ServerInstance) Handshake(conn net.Conn) (*CommonConn, error) {
208213
if _, err := io.ReadFull(conn, encryptedPfsPublicKey); err != nil {
209214
return nil, err
210215
}
211-
if _, err := nfsGCM.Open(encryptedPfsPublicKey[:0], nil, encryptedPfsPublicKey, nil); err != nil {
216+
if _, err := nfsAEAD.Open(encryptedPfsPublicKey[:0], nil, encryptedPfsPublicKey, nil); err != nil {
212217
return nil, err
213218
}
214219
mlkem768EKey, err := mlkem.NewEncapsulationKey768(encryptedPfsPublicKey[:1184])
@@ -230,8 +235,8 @@ func (i *ServerInstance) Handshake(conn net.Conn) (*CommonConn, error) {
230235
copy(pfsKey[32:], x25519Key)
231236
pfsPublicKey := append(encapsulatedPfsKey, x25519SKey.PublicKey().Bytes()...)
232237
c.UnitedKey = append(pfsKey, nfsKey...)
233-
c.GCM = NewGCM(pfsPublicKey, c.UnitedKey)
234-
c.PeerGCM = NewGCM(encryptedPfsPublicKey[:1184+32], c.UnitedKey)
238+
c.AEAD = NewAEAD(pfsPublicKey, c.UnitedKey, c.UseAES)
239+
c.PeerAEAD = NewAEAD(encryptedPfsPublicKey[:1184+32], c.UnitedKey, c.UseAES)
235240
ticket := make([]byte, 16)
236241
rand.Read(ticket)
237242
copy(ticket, EncodeLength(int(i.Seconds*4/5)))
@@ -240,11 +245,11 @@ func (i *ServerInstance) Handshake(conn net.Conn) (*CommonConn, error) {
240245
encryptedTicketLength := 32
241246
paddingLength := int(crypto.RandBetween(100, 1000))
242247
serverHello := make([]byte, pfsKeyExchangeLength+encryptedTicketLength+paddingLength)
243-
nfsGCM.Seal(serverHello[:0], MaxNonce, pfsPublicKey, nil)
244-
c.GCM.Seal(serverHello[:pfsKeyExchangeLength], nil, ticket, nil)
248+
nfsAEAD.Seal(serverHello[:0], MaxNonce, pfsPublicKey, nil)
249+
c.AEAD.Seal(serverHello[:pfsKeyExchangeLength], nil, ticket, nil)
245250
padding := serverHello[pfsKeyExchangeLength+encryptedTicketLength:]
246-
c.GCM.Seal(padding[:0], nil, EncodeLength(paddingLength-18), nil)
247-
c.GCM.Seal(padding[:18], nil, padding[18:paddingLength-16], nil)
251+
c.AEAD.Seal(padding[:0], nil, EncodeLength(paddingLength-18), nil)
252+
c.AEAD.Seal(padding[:18], nil, padding[18:paddingLength-16], nil)
248253

249254
if _, err := conn.Write(serverHello); err != nil {
250255
return nil, err
@@ -264,14 +269,14 @@ func (i *ServerInstance) Handshake(conn net.Conn) (*CommonConn, error) {
264269
if _, err := io.ReadFull(conn, encryptedLength); err != nil {
265270
return nil, err
266271
}
267-
if _, err := nfsGCM.Open(encryptedLength[:0], nil, encryptedLength, nil); err != nil {
272+
if _, err := nfsAEAD.Open(encryptedLength[:0], nil, encryptedLength, nil); err != nil {
268273
return nil, err
269274
}
270275
encryptedPadding := make([]byte, DecodeLength(encryptedLength[:2]))
271276
if _, err := io.ReadFull(conn, encryptedPadding); err != nil {
272277
return nil, err
273278
}
274-
if _, err := nfsGCM.Open(encryptedPadding[:0], nil, encryptedPadding, nil); err != nil {
279+
if _, err := nfsAEAD.Open(encryptedPadding[:0], nil, encryptedPadding, nil); err != nil {
275280
return nil, err
276281
}
277282

0 commit comments

Comments
 (0)