mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2025-12-19 08:20:05 +08:00
chore: sync vless encryption code
This commit is contained in:
parent
65d3920f02
commit
8eba1c8afd
@ -1375,7 +1375,8 @@ listeners:
|
||||
# grpc-service-name: "GunService" # 如果不为空则开启 grpc 传输层
|
||||
# -------------------------
|
||||
# vless encryption服务端配置:
|
||||
# (原生外观 / 只 XOR 公钥 / 全随机数。只允许 1-RTT 模式 / 同时允许 1-RTT 模式与 600 秒复用的 0-RTT 模式)
|
||||
# (原生外观 / 只 XOR 公钥 / 全随机数。1-RTT 每次下发随机 300 到 600 秒的 ticket 以便 0-RTT 复用 / 只允许 1-RTT)
|
||||
# 填写 "600s" 会每次随机取 50% 到 100%,即相当于填写 "300-600s"
|
||||
# / 是只能选一个,后面 base64 至少一个,无限串联,使用 mihomo generate vless-x25519 和 mihomo generate vless-mlkem768 生成,替换值时需去掉括号
|
||||
#
|
||||
# Padding 是可选的参数,仅作用于 1-RTT 以消除握手的长度特征,双端默认值均为 "100-111-1111.75-0-111.50-0-3333":
|
||||
@ -1384,7 +1385,7 @@ listeners:
|
||||
# 再次以 50% 的概率发送随机 0 到 3333 字节的 padding(若为 0 则不 Write())
|
||||
# 服务端、客户端可以设置不同的 padding 参数,按 len、gap 的顺序无限串联,第一个 padding 需概率 100%、至少 35 字节
|
||||
# -------------------------
|
||||
# decryption: "mlkem768x25519plus.native/xorpub/random.1rtt/600s.(padding len).(padding gap).(X25519 PrivateKey).(ML-KEM-768 Seed)..."
|
||||
# decryption: "mlkem768x25519plus.native/xorpub/random.600s(300-600s)/0s.(padding len).(padding gap).(X25519 PrivateKey).(ML-KEM-768 Seed)..."
|
||||
# 下面两项如果填写则开启 tls(需要同时填写)
|
||||
# certificate: ./server.crt
|
||||
# private-key: ./server.key
|
||||
|
||||
@ -100,7 +100,7 @@ func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition)
|
||||
if sl.decryption != nil {
|
||||
defer func() { // decryption must be closed to avoid the goroutine leak
|
||||
if err != nil {
|
||||
_ = sl.decryption.Close()
|
||||
//_ = sl.decryption.Close()
|
||||
sl.decryption = nil
|
||||
}
|
||||
}()
|
||||
@ -210,7 +210,7 @@ func (l *Listener) Close() error {
|
||||
}
|
||||
}
|
||||
if l.decryption != nil {
|
||||
_ = l.decryption.Close()
|
||||
//_ = l.decryption.Close()
|
||||
}
|
||||
return retErr
|
||||
}
|
||||
|
||||
@ -25,4 +25,5 @@
|
||||
// https://github.com/XTLS/Xray-core/commit/e8b02cd6649f14889841e8ab8ee6b2acca71dbe6
|
||||
// https://github.com/XTLS/Xray-core/commit/6768a22f676c9121cfc9dc4f51181a8a07837c8d
|
||||
// https://github.com/XTLS/Xray-core/commit/4c6fd94d97159f5a3e740ba6dd2d9b65e3ed320c
|
||||
// https://github.com/XTLS/Xray-core/commit/19f890729656bc923ae3dee8426168c93b8ee9c2
|
||||
package encryption
|
||||
|
||||
@ -77,17 +77,19 @@ func NewServer(decryption string) (*ServerInstance, error) {
|
||||
default:
|
||||
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
|
||||
}
|
||||
var seconds uint32
|
||||
if s[2] != "1rtt" {
|
||||
t := strings.TrimSuffix(s[2], "s")
|
||||
if t == s[0] {
|
||||
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
|
||||
}
|
||||
i, err := strconv.Atoi(t)
|
||||
t := strings.SplitN(strings.TrimSuffix(s[2], "s"), "-", 2)
|
||||
i, err := strconv.Atoi(t[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
|
||||
}
|
||||
secondsFrom := uint32(i)
|
||||
var secondsTo uint32
|
||||
if len(t) > 1 {
|
||||
i, err = strconv.Atoi(t[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invaild vless decryption value: %s", decryption)
|
||||
}
|
||||
seconds = uint32(i)
|
||||
secondsTo = uint32(i)
|
||||
}
|
||||
var nfsSKeysBytes [][]byte
|
||||
var paddings []string
|
||||
@ -107,7 +109,7 @@ func NewServer(decryption string) (*ServerInstance, error) {
|
||||
}
|
||||
padding := strings.Join(paddings, ".")
|
||||
server := &ServerInstance{}
|
||||
if err := server.Init(nfsSKeysBytes, xorMode, seconds, padding); err != nil {
|
||||
if err := server.Init(nfsSKeysBytes, xorMode, secondsFrom, secondsTo, padding); err != nil {
|
||||
return nil, fmt.Errorf("failed to use decryption: %w", err)
|
||||
}
|
||||
return server, nil
|
||||
|
||||
@ -17,7 +17,6 @@ import (
|
||||
)
|
||||
|
||||
type ServerSession struct {
|
||||
Expire time.Time
|
||||
PfsKey []byte
|
||||
NfsKeys sync.Map
|
||||
}
|
||||
@ -28,16 +27,16 @@ type ServerInstance struct {
|
||||
Hash32s [][32]byte
|
||||
RelaysLength int
|
||||
XorMode uint32
|
||||
Seconds uint32
|
||||
SecondsFrom uint32
|
||||
SecondsTo uint32
|
||||
PaddingLens [][3]int
|
||||
PaddingGaps [][3]int
|
||||
|
||||
RWLock sync.RWMutex
|
||||
Sessions map[[16]byte]*ServerSession
|
||||
Closed bool
|
||||
}
|
||||
|
||||
func (i *ServerInstance) Init(nfsSKeysBytes [][]byte, xorMode, seconds uint32, padding string) (err error) {
|
||||
func (i *ServerInstance) Init(nfsSKeysBytes [][]byte, xorMode, secondsFrom, secondsTo uint32, padding string) (err error) {
|
||||
if i.NfsSKeys != nil {
|
||||
return errors.New("already initialized")
|
||||
}
|
||||
@ -66,37 +65,12 @@ func (i *ServerInstance) Init(nfsSKeysBytes [][]byte, xorMode, seconds uint32, p
|
||||
}
|
||||
i.RelaysLength -= 32
|
||||
i.XorMode = xorMode
|
||||
if seconds > 0 {
|
||||
i.Seconds = seconds
|
||||
i.Sessions = make(map[[16]byte]*ServerSession)
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(time.Minute)
|
||||
i.RWLock.Lock()
|
||||
if i.Closed {
|
||||
i.RWLock.Unlock()
|
||||
return
|
||||
}
|
||||
now := time.Now()
|
||||
for ticket, session := range i.Sessions {
|
||||
if now.After(session.Expire) {
|
||||
delete(i.Sessions, ticket)
|
||||
}
|
||||
}
|
||||
i.RWLock.Unlock()
|
||||
}
|
||||
}()
|
||||
}
|
||||
i.SecondsFrom = secondsFrom
|
||||
i.SecondsTo = secondsTo
|
||||
i.Sessions = make(map[[16]byte]*ServerSession)
|
||||
return ParsePadding(padding, &i.PaddingLens, &i.PaddingGaps)
|
||||
}
|
||||
|
||||
func (i *ServerInstance) Close() (err error) {
|
||||
i.RWLock.Lock()
|
||||
i.Closed = true
|
||||
i.RWLock.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
func (i *ServerInstance) Handshake(conn net.Conn, fallback *[]byte) (*CommonConn, error) {
|
||||
if i.NfsSKeys == nil {
|
||||
return nil, errors.New("uninitialized")
|
||||
@ -131,7 +105,7 @@ func (i *ServerInstance) Handshake(conn net.Conn, fallback *[]byte) (*CommonConn
|
||||
return nil, err
|
||||
}
|
||||
if publicKey.Bytes()[31] > 127 { // we just don't want the observer can change even one bit without breaking the connection, though it has nothing to do with security
|
||||
return nil, errors.New("the highest bit of the last byte of the peer-sent X25519 public key must be 0")
|
||||
return nil, errors.New("the highest bit of the last byte of the peer-sent X25519 public key is not 0")
|
||||
}
|
||||
nfsKey, err = k.ECDH(publicKey)
|
||||
if err != nil {
|
||||
@ -179,7 +153,7 @@ func (i *ServerInstance) Handshake(conn net.Conn, fallback *[]byte) (*CommonConn
|
||||
length := DecodeLength(decryptedLength)
|
||||
|
||||
if length == 32 {
|
||||
if i.Seconds == 0 {
|
||||
if i.SecondsFrom == 0 && i.SecondsTo == 0 {
|
||||
return nil, errors.New("0-RTT is not allowed")
|
||||
}
|
||||
encryptedTicket := make([]byte, 32)
|
||||
@ -251,14 +225,23 @@ func (i *ServerInstance) Handshake(conn net.Conn, fallback *[]byte) (*CommonConn
|
||||
|
||||
ticket := make([]byte, 16)
|
||||
rand.Read(ticket)
|
||||
copy(ticket, EncodeLength(int(i.Seconds*4/5)))
|
||||
if i.Seconds > 0 {
|
||||
seconds := 0
|
||||
if i.SecondsTo == 0 {
|
||||
seconds = int(i.SecondsFrom) * int(randBetween(50, 100)) / 100
|
||||
} else {
|
||||
seconds = int(randBetween(int64(i.SecondsFrom), int64(i.SecondsTo)))
|
||||
}
|
||||
copy(ticket, EncodeLength(int(seconds)))
|
||||
if seconds > 0 {
|
||||
i.RWLock.Lock()
|
||||
i.Sessions[[16]byte(ticket)] = &ServerSession{
|
||||
Expire: time.Now().Add(time.Duration(i.Seconds) * time.Second),
|
||||
PfsKey: pfsKey,
|
||||
}
|
||||
i.Sessions[[16]byte(ticket)] = &ServerSession{PfsKey: pfsKey}
|
||||
i.RWLock.Unlock()
|
||||
go func() {
|
||||
time.Sleep(time.Duration(seconds)*time.Second + time.Minute)
|
||||
i.RWLock.Lock()
|
||||
delete(i.Sessions, [16]byte(ticket))
|
||||
i.RWLock.Unlock()
|
||||
}()
|
||||
}
|
||||
|
||||
pfsKeyExchangeLength := 1088 + 32 + 16
|
||||
|
||||
Loading…
Reference in New Issue
Block a user