1
0
mirror of https://github.com/MetaCubeX/mihomo.git synced 2025-09-20 04:25:59 +08:00
Files
mihomo/transport/vless/encryption/server.go

301 lines
7.3 KiB
Go
Raw Normal View History

2025-08-10 22:16:25 +08:00
package encryption
import (
"bytes"
"crypto/cipher"
"crypto/rand"
2025-08-14 09:57:20 +08:00
"crypto/sha256"
2025-08-10 22:16:25 +08:00
"errors"
2025-08-13 18:51:47 +08:00
"fmt"
2025-08-10 22:16:25 +08:00
"io"
"net"
"sync"
"time"
"github.com/metacubex/utls/mlkem"
)
type ServerSession struct {
expire time.Time
cipher byte
baseKey []byte
randoms sync.Map
}
type ServerInstance struct {
sync.RWMutex
2025-08-14 18:31:56 +08:00
nfsDKey *mlkem.DecapsulationKey768
2025-08-18 08:43:17 +08:00
hash11 [11]byte // no more capacity
2025-08-14 18:31:56 +08:00
xorKey []byte
minutes time.Duration
2025-08-18 08:43:17 +08:00
sessions map[[32]byte]*ServerSession
2025-08-14 18:31:56 +08:00
closed bool
2025-08-10 22:16:25 +08:00
}
type ServerConn struct {
net.Conn
cipher byte
baseKey []byte
ticket []byte
2025-08-10 22:16:25 +08:00
peerRandom []byte
peerAead cipher.AEAD
peerNonce []byte
2025-08-18 09:34:20 +08:00
input bytes.Reader // peerCache
2025-08-10 22:16:25 +08:00
aead cipher.AEAD
nonce []byte
}
2025-08-12 20:06:08 +08:00
func (i *ServerInstance) Init(nfsDKeySeed []byte, xor uint32, minutes time.Duration) (err error) {
2025-08-14 18:31:56 +08:00
if i.nfsDKey != nil {
err = errors.New("already initialized")
return
}
2025-08-12 20:06:08 +08:00
i.nfsDKey, err = mlkem.NewDecapsulationKey768(nfsDKeySeed)
2025-08-14 18:31:56 +08:00
if err != nil {
return
}
2025-08-18 08:43:17 +08:00
hash256 := sha256.Sum256(i.nfsDKey.EncapsulationKey().Bytes())
copy(i.hash11[:], hash256[:])
2025-08-12 20:06:08 +08:00
if xor > 0 {
2025-08-14 18:31:56 +08:00
xorKey := sha256.Sum256(i.nfsDKey.EncapsulationKey().Bytes())
i.xorKey = xorKey[:]
2025-08-12 20:06:08 +08:00
}
2025-08-10 22:16:25 +08:00
if minutes > 0 {
i.minutes = minutes
2025-08-18 08:43:17 +08:00
i.sessions = make(map[[32]byte]*ServerSession)
2025-08-10 22:16:25 +08:00
go func() {
for {
time.Sleep(time.Minute)
i.Lock()
2025-08-13 01:14:22 +08:00
if i.closed {
i.Unlock()
2025-08-10 22:43:31 +08:00
return
}
2025-08-13 18:51:47 +08:00
now := time.Now()
2025-08-12 20:06:08 +08:00
for ticket, session := range i.sessions {
2025-08-10 22:16:25 +08:00
if now.After(session.expire) {
2025-08-12 20:06:08 +08:00
delete(i.sessions, ticket)
2025-08-10 22:16:25 +08:00
}
}
i.Unlock()
}
}()
}
return
}
2025-08-10 22:43:31 +08:00
func (i *ServerInstance) Close() (err error) {
i.Lock()
2025-08-13 01:14:22 +08:00
i.closed = true
i.Unlock()
2025-08-10 22:43:31 +08:00
return
}
2025-08-10 22:16:25 +08:00
func (i *ServerInstance) Handshake(conn net.Conn) (net.Conn, error) {
2025-08-12 20:06:08 +08:00
if i.nfsDKey == nil {
2025-08-10 22:16:25 +08:00
return nil, errors.New("uninitialized")
}
2025-08-14 18:31:56 +08:00
if i.xorKey != nil {
conn = NewXorConn(conn, i.xorKey)
}
2025-08-10 22:16:25 +08:00
c := &ServerConn{Conn: conn}
2025-08-14 23:52:05 +08:00
_, t, l, err := ReadAndDiscardPaddings(c.Conn) // allow paddings before client/ticket hello
2025-08-13 18:51:47 +08:00
if err != nil {
2025-08-10 22:16:25 +08:00
return nil, err
}
2025-08-13 18:51:47 +08:00
if t == 0 {
if i.minutes == 0 {
return nil, errors.New("0-RTT is not allowed")
}
2025-08-18 08:43:17 +08:00
peerTicketHello := make([]byte, 32+32)
2025-08-13 18:51:47 +08:00
if l != len(peerTicketHello) {
return nil, fmt.Errorf("unexpected length %v for ticket hello", l)
}
if _, err := io.ReadFull(c.Conn, peerTicketHello); err != nil {
return nil, err
}
2025-08-18 08:43:17 +08:00
if !bytes.Equal(peerTicketHello[:11], i.hash11[:]) {
return nil, fmt.Errorf("unexpected hash11: %v", peerTicketHello[:11])
}
2025-08-10 22:16:25 +08:00
i.RLock()
2025-08-18 08:43:17 +08:00
s := i.sessions[[32]byte(peerTicketHello)]
2025-08-10 22:16:25 +08:00
i.RUnlock()
2025-08-13 18:51:47 +08:00
if s == nil {
2025-08-14 23:52:05 +08:00
noises := make([]byte, randBetween(100, 1000))
var err error
for err == nil {
rand.Read(noises)
_, _, err = DecodeHeader(noises)
}
c.Conn.Write(noises) // make client do new handshake
2025-08-13 18:51:47 +08:00
return nil, errors.New("expired ticket")
2025-08-10 22:16:25 +08:00
}
2025-08-18 08:43:17 +08:00
if _, replay := s.randoms.LoadOrStore([32]byte(peerTicketHello[32:]), true); replay {
2025-08-13 18:51:47 +08:00
return nil, errors.New("replay detected")
}
c.cipher = s.cipher
c.baseKey = s.baseKey
2025-08-18 08:43:17 +08:00
c.ticket = peerTicketHello[:32]
c.peerRandom = peerTicketHello[32:]
2025-08-13 18:51:47 +08:00
return c, nil
2025-08-10 22:16:25 +08:00
}
2025-08-18 08:43:17 +08:00
peerClientHello := make([]byte, 11+1+1184+1088)
2025-08-13 18:51:47 +08:00
if l != len(peerClientHello) {
return nil, fmt.Errorf("unexpected length %v for client hello", l)
}
if _, err := io.ReadFull(c.Conn, peerClientHello); err != nil {
2025-08-10 22:16:25 +08:00
return nil, err
}
2025-08-18 08:43:17 +08:00
if !bytes.Equal(peerClientHello[:11], i.hash11[:]) {
return nil, fmt.Errorf("unexpected hash11: %v", peerClientHello[:11])
}
c.cipher = peerClientHello[11]
pfsEKeyBytes := peerClientHello[11+1 : 11+1+1184]
encapsulatedNfsKey := peerClientHello[11+1+1184:]
2025-08-10 22:16:25 +08:00
2025-08-12 20:06:08 +08:00
pfsEKey, err := mlkem.NewEncapsulationKey768(pfsEKeyBytes)
2025-08-10 22:16:25 +08:00
if err != nil {
return nil, err
}
2025-08-12 20:06:08 +08:00
nfsKey, err := i.nfsDKey.Decapsulate(encapsulatedNfsKey)
2025-08-10 22:16:25 +08:00
if err != nil {
return nil, err
}
2025-08-12 20:06:08 +08:00
pfsKey, encapsulatedPfsKey := pfsEKey.Encapsulate()
c.baseKey = append(pfsKey, nfsKey...)
2025-08-10 22:16:25 +08:00
2025-08-18 08:43:17 +08:00
c.ticket = append(i.hash11[:], NewAead(c.cipher, c.baseKey, encapsulatedPfsKey, encapsulatedNfsKey).Seal(nil, peerClientHello[:12], []byte("VLESS"), pfsEKeyBytes)...)
2025-08-10 22:16:25 +08:00
2025-08-12 20:06:08 +08:00
paddingLen := randBetween(100, 1000)
2025-08-10 22:16:25 +08:00
2025-08-13 18:51:47 +08:00
serverHello := make([]byte, 5+1088+21+5+paddingLen)
EncodeHeader(serverHello, 1, 1088+21)
copy(serverHello[5:], encapsulatedPfsKey)
2025-08-18 08:43:17 +08:00
copy(serverHello[5+1088:], c.ticket[11:])
2025-08-13 18:51:47 +08:00
EncodeHeader(serverHello[5+1088+21:], 23, int(paddingLen))
rand.Read(serverHello[5+1088+21+5:])
2025-08-10 22:16:25 +08:00
2025-08-13 20:50:46 +08:00
if _, err := c.Conn.Write(serverHello); err != nil {
2025-08-10 22:16:25 +08:00
return nil, err
}
2025-08-14 23:52:05 +08:00
// server can send more paddings / PFS AEAD messages if needed
2025-08-10 22:16:25 +08:00
if i.minutes > 0 {
i.Lock()
2025-08-18 08:43:17 +08:00
i.sessions[[32]byte(c.ticket)] = &ServerSession{
2025-08-10 22:16:25 +08:00
expire: time.Now().Add(i.minutes),
cipher: c.cipher,
baseKey: c.baseKey,
}
i.Unlock()
}
return c, nil
}
func (c *ServerConn) Read(b []byte) (int, error) {
if len(b) == 0 {
return 0, nil
}
if c.peerAead == nil {
2025-08-14 23:52:05 +08:00
if c.peerRandom == nil { // 1-RTT's 0-RTT
_, t, l, err := ReadAndDiscardPaddings(c.Conn) // allow paddings before ticket hello
2025-08-14 18:31:56 +08:00
if err != nil {
return 0, err
2025-08-10 22:16:25 +08:00
}
2025-08-13 18:51:47 +08:00
if t != 0 {
return 0, fmt.Errorf("unexpected type %v, expect ticket hello", t)
}
2025-08-18 08:43:17 +08:00
peerTicketHello := make([]byte, 32+32)
2025-08-13 19:50:53 +08:00
if l != len(peerTicketHello) {
2025-08-13 18:51:47 +08:00
return 0, fmt.Errorf("unexpected length %v for ticket hello", l)
}
2025-08-13 19:50:53 +08:00
if _, err := io.ReadFull(c.Conn, peerTicketHello); err != nil {
2025-08-10 22:16:25 +08:00
return 0, err
}
2025-08-18 08:43:17 +08:00
if !bytes.Equal(peerTicketHello[:32], c.ticket) {
2025-08-10 22:16:25 +08:00
return 0, errors.New("naughty boy")
}
2025-08-18 08:43:17 +08:00
c.peerRandom = peerTicketHello[32:]
2025-08-10 22:16:25 +08:00
}
2025-08-12 22:59:25 +08:00
c.peerAead = NewAead(c.cipher, c.baseKey, c.peerRandom, c.ticket)
2025-08-10 22:16:25 +08:00
c.peerNonce = make([]byte, 12)
}
2025-08-18 09:34:20 +08:00
if c.input.Len() > 0 {
return c.input.Read(b)
2025-08-10 22:16:25 +08:00
}
2025-08-13 18:51:47 +08:00
h, t, l, err := ReadAndDecodeHeader(c.Conn) // l: 17~17000
2025-08-10 22:16:25 +08:00
if err != nil {
return 0, err
}
2025-08-13 18:51:47 +08:00
if t != 23 {
return 0, fmt.Errorf("unexpected type %v, expect encrypted data", t)
}
peerData := make([]byte, l)
2025-08-10 22:16:25 +08:00
if _, err := io.ReadFull(c.Conn, peerData); err != nil {
return 0, err
}
2025-08-13 18:51:47 +08:00
dst := peerData[:l-16]
2025-08-10 22:16:25 +08:00
if len(dst) <= len(b) {
2025-08-12 20:06:08 +08:00
dst = b[:len(dst)] // avoids another copy()
2025-08-10 22:16:25 +08:00
}
2025-08-12 22:59:25 +08:00
var peerAead cipher.AEAD
if bytes.Equal(c.peerNonce, MaxNonce) {
2025-08-13 18:51:47 +08:00
peerAead = NewAead(c.cipher, c.baseKey, peerData, h)
2025-08-12 22:59:25 +08:00
}
2025-08-13 18:51:47 +08:00
_, err = c.peerAead.Open(dst[:0], c.peerNonce, peerData, h)
2025-08-12 22:59:25 +08:00
if peerAead != nil {
c.peerAead = peerAead
}
IncreaseNonce(c.peerNonce)
2025-08-10 22:16:25 +08:00
if err != nil {
2025-08-13 18:51:47 +08:00
return 0, err
2025-08-10 22:16:25 +08:00
}
if len(dst) > len(b) {
2025-08-18 09:34:20 +08:00
c.input.Reset(dst[copy(b, dst):])
2025-08-10 22:16:25 +08:00
dst = b // for len(dst)
}
return len(dst), nil
}
2025-08-12 20:06:08 +08:00
func (c *ServerConn) Write(b []byte) (int, error) {
2025-08-10 22:16:25 +08:00
if len(b) == 0 {
return 0, nil
}
2025-08-12 22:59:25 +08:00
var data []byte
2025-08-12 20:06:08 +08:00
for n := 0; n < len(b); {
b := b[n:]
if len(b) > 8192 {
b = b[:8192] // for avoiding another copy() in client's Read()
}
n += len(b)
if c.aead == nil {
if c.peerRandom == nil {
return 0, errors.New("empty c.peerRandom")
}
2025-08-13 18:51:47 +08:00
data = make([]byte, 5+32+5+len(b)+16)
EncodeHeader(data, 0, 32)
rand.Read(data[5 : 5+32])
c.aead = NewAead(c.cipher, c.baseKey, data[5:5+32], c.peerRandom)
2025-08-12 20:06:08 +08:00
c.nonce = make([]byte, 12)
2025-08-13 18:51:47 +08:00
EncodeHeader(data[5+32:], 23, len(b)+16)
c.aead.Seal(data[:5+32+5], c.nonce, b, data[5+32:5+32+5])
2025-08-12 20:06:08 +08:00
} else {
data = make([]byte, 5+len(b)+16)
2025-08-13 18:51:47 +08:00
EncodeHeader(data, 23, len(b)+16)
2025-08-12 20:06:08 +08:00
c.aead.Seal(data[:5], c.nonce, b, data[:5])
2025-08-12 22:59:25 +08:00
if bytes.Equal(c.nonce, MaxNonce) {
2025-08-13 01:14:22 +08:00
c.aead = NewAead(c.cipher, c.baseKey, data[5:], data[:5])
2025-08-12 22:59:25 +08:00
}
2025-08-12 20:06:08 +08:00
}
2025-08-12 22:59:25 +08:00
IncreaseNonce(c.nonce)
2025-08-13 20:50:46 +08:00
if _, err := c.Conn.Write(data); err != nil {
2025-08-12 20:06:08 +08:00
return 0, err
2025-08-10 22:16:25 +08:00
}
}
return len(b), nil
}