chore: sync vless encryption code

This commit is contained in:
wwqgtxx 2025-08-12 22:59:25 +08:00
parent b4c3bbf660
commit 854c6a13c3
4 changed files with 59 additions and 51 deletions

View File

@ -4,7 +4,6 @@ import (
"bytes" "bytes"
"crypto/cipher" "crypto/cipher"
"crypto/rand" "crypto/rand"
"crypto/sha256"
"errors" "errors"
"io" "io"
"net" "net"
@ -13,7 +12,6 @@ import (
"time" "time"
"github.com/metacubex/utls/mlkem" "github.com/metacubex/utls/mlkem"
"golang.org/x/crypto/hkdf"
"golang.org/x/sys/cpu" "golang.org/x/sys/cpu"
) )
@ -101,7 +99,7 @@ func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) {
clientHello[0] = ClientCipher clientHello[0] = ClientCipher
copy(clientHello[1:], pfsEKeyBytes) copy(clientHello[1:], pfsEKeyBytes)
copy(clientHello[1185:], encapsulatedNfsKey) copy(clientHello[1185:], encapsulatedNfsKey)
encodeHeader(clientHello[2273:], int(paddingLen)) EncodeHeader(clientHello[2273:], int(paddingLen))
rand.Read(clientHello[2278:]) rand.Read(clientHello[2278:])
if _, err := c.Conn.Write(clientHello); err != nil { if _, err := c.Conn.Write(clientHello); err != nil {
@ -122,11 +120,9 @@ func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) {
} }
c.baseKey = append(pfsKey, nfsKey...) c.baseKey = append(pfsKey, nfsKey...)
authKey := make([]byte, 32)
hkdf.New(sha256.New, c.baseKey, encapsulatedPfsKey, encapsulatedNfsKey).Read(authKey)
nonce := [12]byte{ClientCipher} nonce := [12]byte{ClientCipher}
VLESS, _ := newAead(ClientCipher, authKey).Open(nil, nonce[:], c.ticket, pfsEKeyBytes) VLESS, _ := NewAead(ClientCipher, c.baseKey, encapsulatedPfsKey, encapsulatedNfsKey).Open(nil, nonce[:], c.ticket, pfsEKeyBytes)
if !bytes.Equal(VLESS, []byte("VLESS")) { // TODO: more message if !bytes.Equal(VLESS, []byte("VLESS")) { // TODO: more messages
return nil, errors.New("invalid server") return nil, errors.New("invalid server")
} }
@ -145,32 +141,32 @@ func (c *ClientConn) Write(b []byte) (int, error) {
if len(b) == 0 { if len(b) == 0 {
return 0, nil return 0, nil
} }
var data []byte
for n := 0; n < len(b); { for n := 0; n < len(b); {
b := b[n:] b := b[n:]
if len(b) > 8192 { if len(b) > 8192 {
b = b[:8192] // for avoiding another copy() in server's Read() b = b[:8192] // for avoiding another copy() in server's Read()
} }
n += len(b) n += len(b)
var data []byte
if c.aead == nil { if c.aead == nil {
c.random = make([]byte, 32) c.random = make([]byte, 32)
rand.Read(c.random) rand.Read(c.random)
key := make([]byte, 32) c.aead = NewAead(ClientCipher, c.baseKey, c.random, c.ticket)
hkdf.New(sha256.New, c.baseKey, c.random, c.ticket).Read(key)
c.aead = newAead(ClientCipher, key)
c.nonce = make([]byte, 12) c.nonce = make([]byte, 12)
data = make([]byte, 21+32+5+len(b)+16) data = make([]byte, 21+32+5+len(b)+16)
copy(data, c.ticket) copy(data, c.ticket)
copy(data[21:], c.random) copy(data[21:], c.random)
encodeHeader(data[53:], len(b)+16) EncodeHeader(data[53:], len(b)+16)
c.aead.Seal(data[:58], c.nonce, b, data[53:58]) c.aead.Seal(data[:58], c.nonce, b, data[53:58])
} else { } else {
data = make([]byte, 5+len(b)+16) data = make([]byte, 5+len(b)+16)
encodeHeader(data, len(b)+16) EncodeHeader(data, len(b)+16)
c.aead.Seal(data[:5], c.nonce, b, data[:5]) 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) IncreaseNonce(c.nonce)
if _, err := c.Conn.Write(data); err != nil { if _, err := c.Conn.Write(data); err != nil {
return 0, err return 0, err
} }
@ -189,7 +185,7 @@ func (c *ClientConn) Read(b []byte) (int, error) {
if _, err := io.ReadFull(c.Conn, peerHeader); err != nil { if _, err := io.ReadFull(c.Conn, peerHeader); err != nil {
return 0, err return 0, err
} }
peerPaddingLen, _ := decodeHeader(peerHeader) peerPaddingLen, _ := DecodeHeader(peerHeader)
if peerPaddingLen == 0 { if peerPaddingLen == 0 {
break break
} }
@ -210,9 +206,7 @@ func (c *ClientConn) Read(b []byte) (int, error) {
if c.random == nil { if c.random == nil {
return 0, errors.New("empty c.random") return 0, errors.New("empty c.random")
} }
peerKey := make([]byte, 32) c.peerAead = NewAead(ClientCipher, c.baseKey, peerRandom, c.random)
hkdf.New(sha256.New, c.baseKey, peerRandom, c.random).Read(peerKey)
c.peerAead = newAead(ClientCipher, peerKey)
c.peerNonce = make([]byte, 12) c.peerNonce = make([]byte, 12)
} }
if len(c.peerCache) != 0 { if len(c.peerCache) != 0 {
@ -223,7 +217,7 @@ func (c *ClientConn) Read(b []byte) (int, error) {
if _, err := io.ReadFull(c.Conn, peerHeader); err != nil { if _, err := io.ReadFull(c.Conn, peerHeader); err != nil {
return 0, err return 0, err
} }
peerLength, err := decodeHeader(peerHeader) // 17~17000 peerLength, err := DecodeHeader(peerHeader) // 17~17000
if err != nil { if err != nil {
if c.instance != nil { if c.instance != nil {
c.instance.Lock() c.instance.Lock()
@ -242,8 +236,15 @@ func (c *ClientConn) Read(b []byte) (int, error) {
if len(dst) <= len(b) { if len(dst) <= len(b) {
dst = b[:len(dst)] // avoids another copy() dst = b[:len(dst)] // avoids another copy()
} }
var peerAead cipher.AEAD
if bytes.Equal(c.peerNonce, MaxNonce) {
peerAead = NewAead(ClientCipher, c.baseKey, peerData, peerHeader)
}
_, err = c.peerAead.Open(dst[:0], c.peerNonce, peerData, peerHeader) _, err = c.peerAead.Open(dst[:0], c.peerNonce, peerData, peerHeader)
increaseNonce(c.peerNonce) if peerAead != nil {
c.peerAead = peerAead
}
IncreaseNonce(c.peerNonce)
if err != nil { if err != nil {
return 0, err return 0, err
} }

View File

@ -1,17 +1,22 @@
package encryption package encryption
import ( import (
"bytes"
"crypto/aes" "crypto/aes"
"crypto/cipher" "crypto/cipher"
"crypto/rand" "crypto/rand"
"crypto/sha256"
"errors" "errors"
"math/big" "math/big"
"strconv" "strconv"
"golang.org/x/crypto/chacha20poly1305" "golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/hkdf"
) )
func encodeHeader(b []byte, l int) { var MaxNonce = bytes.Repeat([]byte{255}, 12)
func EncodeHeader(b []byte, l int) {
b[0] = 23 b[0] = 23
b[1] = 3 b[1] = 3
b[2] = 3 b[2] = 3
@ -19,10 +24,10 @@ func encodeHeader(b []byte, l int) {
b[4] = byte(l) b[4] = byte(l)
} }
func decodeHeader(b []byte) (int, error) { func DecodeHeader(b []byte) (int, error) {
if b[0] == 23 && b[1] == 3 && b[2] == 3 { if b[0] == 23 && b[1] == 3 && b[2] == 3 {
l := int(b[3])<<8 | int(b[4]) l := int(b[3])<<8 | int(b[4])
if l < 17 || l > 17000 { // TODO if l < 17 || l > 17000 { // TODO: TLSv1.3 max length
return 0, errors.New("invalid length in record's header: " + strconv.Itoa(l)) return 0, errors.New("invalid length in record's header: " + strconv.Itoa(l))
} }
return l, nil return l, nil
@ -30,25 +35,24 @@ func decodeHeader(b []byte) (int, error) {
return 0, errors.New("invalid record's header") return 0, errors.New("invalid record's header")
} }
func newAead(c byte, k []byte) (aead cipher.AEAD) { func NewAead(c byte, secret, salt, info []byte) (aead cipher.AEAD) {
key := make([]byte, 32)
hkdf.New(sha256.New, secret, salt, info).Read(key)
if c&1 == 1 { if c&1 == 1 {
block, _ := aes.NewCipher(k) block, _ := aes.NewCipher(key)
aead, _ = cipher.NewGCM(block) aead, _ = cipher.NewGCM(block)
} else { } else {
aead, _ = chacha20poly1305.New(k) aead, _ = chacha20poly1305.New(key)
} }
return return
} }
func increaseNonce(nonce []byte) { func IncreaseNonce(nonce []byte) {
for i := 0; i < 12; i++ { for i := 0; i < 12; i++ {
nonce[11-i]++ nonce[11-i]++
if nonce[11-i] != 0 { if nonce[11-i] != 0 {
break break
} }
if i == 11 {
// TODO
}
} }
} }

View File

@ -3,4 +3,5 @@
// https://github.com/XTLS/Xray-core/commit/3e19bf9233bdd9bafc073a71c65b737cc1ffba5e // https://github.com/XTLS/Xray-core/commit/3e19bf9233bdd9bafc073a71c65b737cc1ffba5e
// https://github.com/XTLS/Xray-core/commit/7ffb555fc8ec51bd1e3e60f26f1d6957984dba80 // https://github.com/XTLS/Xray-core/commit/7ffb555fc8ec51bd1e3e60f26f1d6957984dba80
// https://github.com/XTLS/Xray-core/commit/ec1cc35188c1a5f38a2ff75e88b5d043ffdc59da // https://github.com/XTLS/Xray-core/commit/ec1cc35188c1a5f38a2ff75e88b5d043ffdc59da
// https://github.com/XTLS/Xray-core/commit/5c611420487a92f931faefc01d4bf03869f477f6
package encryption package encryption

View File

@ -4,7 +4,6 @@ import (
"bytes" "bytes"
"crypto/cipher" "crypto/cipher"
"crypto/rand" "crypto/rand"
"crypto/sha256"
"errors" "errors"
"io" "io"
"net" "net"
@ -12,7 +11,6 @@ import (
"time" "time"
"github.com/metacubex/utls/mlkem" "github.com/metacubex/utls/mlkem"
"golang.org/x/crypto/hkdf"
) )
type ServerSession struct { type ServerSession struct {
@ -113,7 +111,7 @@ func (i *ServerInstance) Handshake(conn net.Conn) (net.Conn, error) {
if _, err := io.ReadFull(c.Conn, peerHeader); err != nil { if _, err := io.ReadFull(c.Conn, peerHeader); err != nil {
return nil, err return nil, err
} }
if l, _ := decodeHeader(peerHeader); l != 0 { if l, _ := DecodeHeader(peerHeader); l != 0 {
noise := make([]byte, randBetween(100, 1000)) noise := make([]byte, randBetween(100, 1000))
rand.Read(noise) rand.Read(noise)
c.Conn.Write(noise) // make client do new handshake c.Conn.Write(noise) // make client do new handshake
@ -141,17 +139,15 @@ func (i *ServerInstance) Handshake(conn net.Conn) (net.Conn, error) {
pfsKey, encapsulatedPfsKey := pfsEKey.Encapsulate() pfsKey, encapsulatedPfsKey := pfsEKey.Encapsulate()
c.baseKey = append(pfsKey, nfsKey...) c.baseKey = append(pfsKey, nfsKey...)
authKey := make([]byte, 32)
hkdf.New(sha256.New, c.baseKey, encapsulatedPfsKey, encapsulatedNfsKey).Read(authKey)
nonce := [12]byte{c.cipher} nonce := [12]byte{c.cipher}
c.ticket = newAead(c.cipher, authKey).Seal(nil, nonce[:], []byte("VLESS"), pfsEKeyBytes) c.ticket = NewAead(c.cipher, c.baseKey, encapsulatedPfsKey, encapsulatedNfsKey).Seal(nil, nonce[:], []byte("VLESS"), pfsEKeyBytes)
paddingLen := randBetween(100, 1000) paddingLen := randBetween(100, 1000)
serverHello := make([]byte, 1088+21+5+paddingLen) serverHello := make([]byte, 1088+21+5+paddingLen)
copy(serverHello, encapsulatedPfsKey) copy(serverHello, encapsulatedPfsKey)
copy(serverHello[1088:], c.ticket) copy(serverHello[1088:], c.ticket)
encodeHeader(serverHello[1109:], int(paddingLen)) EncodeHeader(serverHello[1109:], int(paddingLen))
rand.Read(serverHello[1114:]) rand.Read(serverHello[1114:])
if _, err := c.Conn.Write(serverHello); err != nil { if _, err := c.Conn.Write(serverHello); err != nil {
@ -183,7 +179,7 @@ func (c *ServerConn) Read(b []byte) (int, error) {
if _, err := io.ReadFull(c.Conn, peerHeader); err != nil { if _, err := io.ReadFull(c.Conn, peerHeader); err != nil {
return 0, err return 0, err
} }
peerPaddingLen, _ := decodeHeader(peerHeader) peerPaddingLen, _ := DecodeHeader(peerHeader)
if peerPaddingLen == 0 { if peerPaddingLen == 0 {
break break
} }
@ -204,9 +200,7 @@ func (c *ServerConn) Read(b []byte) (int, error) {
return 0, err return 0, err
} }
} }
peerKey := make([]byte, 32) c.peerAead = NewAead(c.cipher, c.baseKey, c.peerRandom, c.ticket)
hkdf.New(sha256.New, c.baseKey, c.peerRandom, c.ticket).Read(peerKey)
c.peerAead = newAead(c.cipher, peerKey)
c.peerNonce = make([]byte, 12) c.peerNonce = make([]byte, 12)
} }
if len(c.peerCache) != 0 { if len(c.peerCache) != 0 {
@ -217,7 +211,7 @@ func (c *ServerConn) Read(b []byte) (int, error) {
if _, err := io.ReadFull(c.Conn, peerHeader); err != nil { if _, err := io.ReadFull(c.Conn, peerHeader); err != nil {
return 0, err return 0, err
} }
peerLength, err := decodeHeader(peerHeader) // 17~17000 peerLength, err := DecodeHeader(peerHeader) // 17~17000
if err != nil { if err != nil {
return 0, err return 0, err
} }
@ -229,8 +223,15 @@ func (c *ServerConn) Read(b []byte) (int, error) {
if len(dst) <= len(b) { if len(dst) <= len(b) {
dst = b[:len(dst)] // avoids another copy() dst = b[:len(dst)] // avoids another copy()
} }
var peerAead cipher.AEAD
if bytes.Equal(c.peerNonce, MaxNonce) {
peerAead = NewAead(ClientCipher, c.baseKey, peerData, peerHeader)
}
_, err = c.peerAead.Open(dst[:0], c.peerNonce, peerData, peerHeader) _, err = c.peerAead.Open(dst[:0], c.peerNonce, peerData, peerHeader)
increaseNonce(c.peerNonce) if peerAead != nil {
c.peerAead = peerAead
}
IncreaseNonce(c.peerNonce)
if err != nil { if err != nil {
return 0, errors.New("error") return 0, errors.New("error")
} }
@ -245,31 +246,32 @@ func (c *ServerConn) Write(b []byte) (int, error) {
if len(b) == 0 { if len(b) == 0 {
return 0, nil return 0, nil
} }
var data []byte
for n := 0; n < len(b); { for n := 0; n < len(b); {
b := b[n:] b := b[n:]
if len(b) > 8192 { if len(b) > 8192 {
b = b[:8192] // for avoiding another copy() in client's Read() b = b[:8192] // for avoiding another copy() in client's Read()
} }
n += len(b) n += len(b)
var data []byte
if c.aead == nil { if c.aead == nil {
if c.peerRandom == nil { if c.peerRandom == nil {
return 0, errors.New("empty c.peerRandom") return 0, errors.New("empty c.peerRandom")
} }
data = make([]byte, 32+5+len(b)+16) data = make([]byte, 32+5+len(b)+16)
rand.Read(data[:32]) rand.Read(data[:32])
key := make([]byte, 32) c.aead = NewAead(c.cipher, c.baseKey, data[:32], c.peerRandom)
hkdf.New(sha256.New, c.baseKey, data[:32], c.peerRandom).Read(key)
c.aead = newAead(c.cipher, key)
c.nonce = make([]byte, 12) c.nonce = make([]byte, 12)
encodeHeader(data[32:], len(b)+16) EncodeHeader(data[32:], len(b)+16)
c.aead.Seal(data[:37], c.nonce, b, data[32:37]) c.aead.Seal(data[:37], c.nonce, b, data[32:37])
} else { } else {
data = make([]byte, 5+len(b)+16) data = make([]byte, 5+len(b)+16)
encodeHeader(data, len(b)+16) EncodeHeader(data, len(b)+16)
c.aead.Seal(data[:5], c.nonce, b, data[:5]) 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) IncreaseNonce(c.nonce)
if _, err := c.Conn.Write(data); err != nil { if _, err := c.Conn.Write(data); err != nil {
return 0, err return 0, err
} }