Add optional aes128xor layer

https://github.com/XTLS/Xray-core/pull/4952#issuecomment-3172703168
This commit is contained in:
RPRX
2025-08-11 12:07:00 +00:00
committed by GitHub
parent 2e6a88307c
commit 7ffb555fc8
11 changed files with 146 additions and 36 deletions

View File

@@ -28,6 +28,7 @@ func init() {
type ClientInstance struct {
sync.RWMutex
eKeyNfs *mlkem.EncapsulationKey768
xor uint32
minutes time.Duration
expire time.Time
baseKey []byte
@@ -47,8 +48,9 @@ type ClientConn struct {
peerCache []byte
}
func (i *ClientInstance) Init(eKeyNfsData []byte, minutes time.Duration) (err error) {
func (i *ClientInstance) Init(eKeyNfsData []byte, xor uint32, minutes time.Duration) (err error) {
i.eKeyNfs, err = mlkem.NewEncapsulationKey768(eKeyNfsData)
i.xor = xor
i.minutes = minutes
return
}
@@ -57,6 +59,9 @@ func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) {
if i.eKeyNfs == nil {
return nil, errors.New("uninitialized")
}
if i.xor == 1 {
conn = NewXorConn(conn, i.eKeyNfs.Bytes())
}
c := &ClientConn{Conn: conn}
if i.minutes > 0 {

View File

@@ -26,6 +26,7 @@ type ServerSession struct {
type ServerInstance struct {
sync.RWMutex
dKeyNfs *mlkem.DecapsulationKey768
xor uint32
minutes time.Duration
sessions map[[21]byte]*ServerSession
}
@@ -43,8 +44,9 @@ type ServerConn struct {
nonce []byte
}
func (i *ServerInstance) Init(dKeyNfsData []byte, minutes time.Duration) (err error) {
func (i *ServerInstance) Init(dKeyNfsData []byte, xor uint32, minutes time.Duration) (err error) {
i.dKeyNfs, err = mlkem.NewDecapsulationKey768(dKeyNfsData)
i.xor = xor
if minutes > 0 {
i.minutes = minutes
i.sessions = make(map[[21]byte]*ServerSession)
@@ -69,6 +71,9 @@ func (i *ServerInstance) Handshake(conn net.Conn) (net.Conn, error) {
if i.dKeyNfs == nil {
return nil, errors.New("uninitialized")
}
if i.xor == 1 {
conn = NewXorConn(conn, i.dKeyNfs.EncapsulationKey().Bytes())
}
c := &ServerConn{Conn: conn}
peerTicketHello := make([]byte, 21+32)

View File

@@ -0,0 +1,63 @@
package encryption
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"io"
"net"
)
type XorConn struct {
net.Conn
key []byte
ctr cipher.Stream
peerCtr cipher.Stream
}
func NewXorConn(conn net.Conn, key []byte) *XorConn {
return &XorConn{Conn: conn, key: key[:16]}
}
func (c *XorConn) Write(b []byte) (int, error) {
if len(b) == 0 {
return 0, nil
}
var iv []byte
if c.ctr == nil {
block, _ := aes.NewCipher(c.key)
iv = make([]byte, 16)
rand.Read(iv)
c.ctr = cipher.NewCTR(block, iv)
}
c.ctr.XORKeyStream(b, b) // caller MUST discard b
if iv != nil {
b = append(iv, b...)
}
if _, err := c.Conn.Write(b); err != nil {
return 0, err
}
if iv != nil {
b = b[16:]
}
return len(b), nil
}
func (c *XorConn) Read(b []byte) (int, error) {
if len(b) == 0 {
return 0, nil
}
if c.peerCtr == nil {
peerIv := make([]byte, 16)
if _, err := io.ReadFull(c.Conn, peerIv); err != nil {
return 0, err
}
block, _ := aes.NewCipher(c.key)
c.peerCtr = cipher.NewCTR(block, peerIv)
}
n, err := c.Conn.Read(b)
if n > 0 {
c.peerCtr.XORKeyStream(b[:n], b[:n])
}
return n, err
}