Add 5-bytes header for client/server/ticket hello and server random

https://github.com/XTLS/Xray-core/pull/4952#issuecomment-3182301703
This commit is contained in:
RPRX
2025-08-13 09:17:37 +00:00
committed by GitHub
parent 23d7aad461
commit 3c20bddfcf
3 changed files with 178 additions and 112 deletions

View File

@@ -85,19 +85,31 @@ func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) {
nfsKey, encapsulatedNfsKey := i.nfsEKey.Encapsulate()
paddingLen := crypto.RandBetween(100, 1000)
clientHello := make([]byte, 1+1184+1088+5+paddingLen)
clientHello[0] = ClientCipher
copy(clientHello[1:], pfsEKeyBytes)
copy(clientHello[1185:], encapsulatedNfsKey)
EncodeHeader(clientHello[2273:], int(paddingLen))
rand.Read(clientHello[2278:])
clientHello := make([]byte, 5+1+1184+1088+5+paddingLen)
EncodeHeader(clientHello, 1, 1+1184+1088)
clientHello[5] = ClientCipher
copy(clientHello[5+1:], pfsEKeyBytes)
copy(clientHello[5+1+1184:], encapsulatedNfsKey)
EncodeHeader(clientHello[5+1+1184+1088:], 23, int(paddingLen))
rand.Read(clientHello[5+1+1184+1088+5:])
if _, err := c.Conn.Write(clientHello); err != nil {
if n, err := c.Conn.Write(clientHello); n != len(clientHello) || err != nil {
return nil, err
}
// we can send more padding if needed
// client can send more padding / NFS AEAD messages if needed
_, t, l, err := ReadAndDecodeHeader(c.Conn)
if err != nil {
return nil, err
}
if t != 1 {
return nil, errors.New("unexpected type ", t, ", expect server hello")
}
peerServerHello := make([]byte, 1088+21)
if l != len(peerServerHello) {
return nil, errors.New("unexpected length ", l, " for server hello")
}
if _, err := io.ReadFull(c.Conn, peerServerHello); err != nil {
return nil, err
}
@@ -112,7 +124,7 @@ func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) {
nonce := [12]byte{ClientCipher}
VLESS, _ := NewAead(ClientCipher, c.baseKey, encapsulatedPfsKey, encapsulatedNfsKey).Open(nil, nonce[:], c.ticket, pfsEKeyBytes)
if !bytes.Equal(VLESS, []byte("VLESS")) { // TODO: more messages
if !bytes.Equal(VLESS, []byte("VLESS")) {
return nil, errors.New("invalid server").AtError()
}
@@ -143,21 +155,22 @@ func (c *ClientConn) Write(b []byte) (int, error) {
rand.Read(c.random)
c.aead = NewAead(ClientCipher, c.baseKey, c.random, c.ticket)
c.nonce = make([]byte, 12)
data = make([]byte, 21+32+5+len(b)+16)
copy(data, c.ticket)
copy(data[21:], c.random)
EncodeHeader(data[53:], len(b)+16)
c.aead.Seal(data[:58], c.nonce, b, data[53:58])
data = make([]byte, 5+21+32+5+len(b)+16)
EncodeHeader(data, 0, 21+32)
copy(data[5:], c.ticket)
copy(data[5+21:], c.random)
EncodeHeader(data[5+21+32:], 23, len(b)+16)
c.aead.Seal(data[:5+21+32+5], c.nonce, b, data[5+21+32:5+21+32+5])
} else {
data = make([]byte, 5+len(b)+16)
EncodeHeader(data, len(b)+16)
EncodeHeader(data, 23, len(b)+16)
c.aead.Seal(data[:5], c.nonce, b, data[:5])
if bytes.Equal(c.nonce, MaxNonce) {
c.aead = NewAead(ClientCipher, c.baseKey, data[5:], data[:5])
}
}
IncreaseNonce(c.nonce)
if _, err := c.Conn.Write(data); err != nil {
if n, err := c.Conn.Write(data); n != len(data) || err != nil {
return 0, err
}
}
@@ -168,29 +181,44 @@ func (c *ClientConn) Read(b []byte) (int, error) {
if len(b) == 0 {
return 0, nil
}
peerHeader := make([]byte, 5)
if c.peerAead == nil {
if c.instance == nil {
var t byte
var l int
var err error
if c.instance == nil { // 1-RTT
for {
if _, err := io.ReadFull(c.Conn, peerHeader); err != nil {
if _, t, l, err = ReadAndDecodeHeader(c.Conn); err != nil {
return 0, err
}
peerPaddingLen, _ := DecodeHeader(peerHeader)
if peerPaddingLen == 0 {
if t != 23 {
break
}
if _, err := io.ReadFull(c.Conn, make([]byte, peerPaddingLen)); err != nil {
if _, err := io.ReadFull(c.Conn, make([]byte, l)); err != nil {
return 0, err
}
}
} else {
if _, err := io.ReadFull(c.Conn, peerHeader); err != nil {
h := make([]byte, 5)
if _, err := io.ReadFull(c.Conn, h); err != nil {
return 0, err
}
if t, l, err = DecodeHeader(h); err != nil {
c.instance.Lock()
if bytes.Equal(c.ticket, c.instance.ticket) {
c.instance.expire = time.Now() // expired
}
c.instance.Unlock()
return 0, errors.New("new handshake needed")
}
}
if t != 0 {
return 0, errors.New("unexpected type ", t, ", expect server random")
}
peerRandom := make([]byte, 32)
copy(peerRandom, peerHeader)
if _, err := io.ReadFull(c.Conn, peerRandom[5:]); err != nil {
if l != len(peerRandom) {
return 0, errors.New("unexpected length ", l, " for server random")
}
if _, err := io.ReadFull(c.Conn, peerRandom); err != nil {
return 0, err
}
if c.random == nil {
@@ -204,33 +232,26 @@ func (c *ClientConn) Read(b []byte) (int, error) {
c.peerCache = c.peerCache[n:]
return n, nil
}
if _, err := io.ReadFull(c.Conn, peerHeader); err != nil {
return 0, err
}
peerLength, err := DecodeHeader(peerHeader) // 17~17000
h, t, l, err := ReadAndDecodeHeader(c.Conn) // l: 17~17000
if err != nil {
if c.instance != nil {
c.instance.Lock()
if bytes.Equal(c.ticket, c.instance.ticket) {
c.instance.expire = time.Now() // expired
}
c.instance.Unlock()
}
return 0, err
}
peerData := make([]byte, peerLength)
if t != 23 {
return 0, errors.New("unexpected type ", t, ", expect encrypted data")
}
peerData := make([]byte, l)
if _, err := io.ReadFull(c.Conn, peerData); err != nil {
return 0, err
}
dst := peerData[:peerLength-16]
dst := peerData[:l-16]
if len(dst) <= len(b) {
dst = b[:len(dst)] // avoids another copy()
}
var peerAead cipher.AEAD
if bytes.Equal(c.peerNonce, MaxNonce) {
peerAead = NewAead(ClientCipher, c.baseKey, peerData, peerHeader)
peerAead = NewAead(ClientCipher, c.baseKey, peerData, h)
}
_, err = c.peerAead.Open(dst[:0], c.peerNonce, peerData, peerHeader)
_, err = c.peerAead.Open(dst[:0], c.peerNonce, peerData, h)
if peerAead != nil {
c.peerAead = peerAead
}