mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2025-12-20 00:50:06 +08:00
chore: sync vless encryption code
This commit is contained in:
parent
0836ec6ee3
commit
b643388539
@ -10,6 +10,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -37,13 +38,12 @@ func init() {
|
|||||||
|
|
||||||
type ClientInstance struct {
|
type ClientInstance struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
nfsEKey *mlkem.EncapsulationKey768
|
nfsEKey *mlkem.EncapsulationKey768
|
||||||
nfsEKeySha256 [32]byte
|
xorKey []byte
|
||||||
xor uint32
|
minutes time.Duration
|
||||||
minutes time.Duration
|
expire time.Time
|
||||||
expire time.Time
|
baseKey []byte
|
||||||
baseKey []byte
|
ticket []byte
|
||||||
ticket []byte
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ClientConn struct {
|
type ClientConn struct {
|
||||||
@ -60,10 +60,17 @@ type ClientConn struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *ClientInstance) Init(nfsEKeyBytes []byte, xor uint32, minutes time.Duration) (err error) {
|
func (i *ClientInstance) Init(nfsEKeyBytes []byte, xor uint32, minutes time.Duration) (err error) {
|
||||||
|
if i.nfsEKey != nil {
|
||||||
|
err = errors.New("already initialized")
|
||||||
|
return
|
||||||
|
}
|
||||||
i.nfsEKey, err = mlkem.NewEncapsulationKey768(nfsEKeyBytes)
|
i.nfsEKey, err = mlkem.NewEncapsulationKey768(nfsEKeyBytes)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
if xor > 0 {
|
if xor > 0 {
|
||||||
i.nfsEKeySha256 = sha256.Sum256(nfsEKeyBytes)
|
xorKey := sha256.Sum256(nfsEKeyBytes)
|
||||||
i.xor = xor
|
i.xorKey = xorKey[:]
|
||||||
}
|
}
|
||||||
i.minutes = minutes
|
i.minutes = minutes
|
||||||
return
|
return
|
||||||
@ -73,8 +80,8 @@ func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) {
|
|||||||
if i.nfsEKey == nil {
|
if i.nfsEKey == nil {
|
||||||
return nil, errors.New("uninitialized")
|
return nil, errors.New("uninitialized")
|
||||||
}
|
}
|
||||||
if i.xor > 0 {
|
if i.xorKey != nil {
|
||||||
conn = NewXorConn(conn, i.nfsEKeySha256[:])
|
conn = NewXorConn(conn, i.xorKey)
|
||||||
}
|
}
|
||||||
c := &ClientConn{Conn: conn}
|
c := &ClientConn{Conn: conn}
|
||||||
|
|
||||||
@ -110,14 +117,14 @@ func (i *ClientInstance) Handshake(conn net.Conn) (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
// client can send more padding / NFS AEAD messages if needed
|
// client can send more padding / NFS AEAD messages if needed
|
||||||
|
|
||||||
_, t, l, err := ReadAndDecodeHeader(c.Conn)
|
_, t, l, err := ReadAndDiscardPaddings(c.Conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if t != 1 {
|
if t != 1 {
|
||||||
return nil, fmt.Errorf("unexpected type %v, expect random hello", t)
|
return nil, fmt.Errorf("unexpected type %v, expect random hello", t)
|
||||||
}
|
}
|
||||||
|
|
||||||
peerRandomHello := make([]byte, 1088+21)
|
peerRandomHello := make([]byte, 1088+21)
|
||||||
if l != len(peerRandomHello) {
|
if l != len(peerRandomHello) {
|
||||||
return nil, fmt.Errorf("unexpected length %v for random hello", l)
|
return nil, fmt.Errorf("unexpected length %v for random hello", l)
|
||||||
@ -194,27 +201,9 @@ func (c *ClientConn) Read(b []byte) (int, error) {
|
|||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
if c.peerAead == nil {
|
if c.peerAead == nil {
|
||||||
var t byte
|
_, t, l, err := ReadAndDiscardPaddings(c.Conn)
|
||||||
var l int
|
if err != nil {
|
||||||
var err error
|
if c.instance != nil && strings.HasPrefix(err.Error(), "invalid header: ") { // from 0-RTT
|
||||||
if c.instance == nil { // from 1-RTT
|
|
||||||
for {
|
|
||||||
if _, t, l, err = ReadAndDecodeHeader(c.Conn); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
if t != 23 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if _, err := io.ReadFull(c.Conn, make([]byte, l)); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
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()
|
c.instance.Lock()
|
||||||
if bytes.Equal(c.ticket, c.instance.ticket) {
|
if bytes.Equal(c.ticket, c.instance.ticket) {
|
||||||
c.instance.expire = time.Now() // expired
|
c.instance.expire = time.Now() // expired
|
||||||
@ -222,6 +211,7 @@ func (c *ClientConn) Read(b []byte) (int, error) {
|
|||||||
c.instance.Unlock()
|
c.instance.Unlock()
|
||||||
return 0, errors.New("new handshake needed")
|
return 0, errors.New("new handshake needed")
|
||||||
}
|
}
|
||||||
|
return 0, err
|
||||||
}
|
}
|
||||||
if t != 0 {
|
if t != 0 {
|
||||||
return 0, fmt.Errorf("unexpected type %v, expect server random", t)
|
return 0, fmt.Errorf("unexpected type %v, expect server random", t)
|
||||||
|
|||||||
@ -45,10 +45,10 @@ func DecodeHeader(h []byte) (t byte, l int, err error) {
|
|||||||
} else if h[0] == 1 && h[1] == 1 && h[2] == 1 {
|
} else if h[0] == 1 && h[1] == 1 && h[2] == 1 {
|
||||||
t = 1
|
t = 1
|
||||||
} else {
|
} else {
|
||||||
h = nil
|
l = 0
|
||||||
}
|
}
|
||||||
if h == nil || l < 17 || l > 17000 { // TODO: TLSv1.3 max length
|
if l < 17 || l > 17000 { // TODO: TLSv1.3 max length
|
||||||
err = fmt.Errorf("invalid header: %v", h[:5])
|
err = fmt.Errorf("invalid header: %v", h[:5]) // relied by client's Read()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -62,6 +62,17 @@ func ReadAndDecodeHeader(conn net.Conn) (h []byte, t byte, l int, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ReadAndDiscardPaddings(conn net.Conn) (h []byte, t byte, l int, err error) {
|
||||||
|
for {
|
||||||
|
if h, t, l, err = ReadAndDecodeHeader(conn); err != nil || t != 23 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, err = io.ReadFull(conn, make([]byte, l)); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func NewAead(c byte, secret, salt, info []byte) (aead cipher.AEAD) {
|
func NewAead(c byte, secret, salt, info []byte) (aead cipher.AEAD) {
|
||||||
key := make([]byte, 32)
|
key := make([]byte, 32)
|
||||||
hkdf.New(sha256.New, secret, salt, info).Read(key)
|
hkdf.New(sha256.New, secret, salt, info).Read(key)
|
||||||
|
|||||||
@ -9,5 +9,5 @@
|
|||||||
// https://github.com/XTLS/Xray-core/commit/1720be168fa069332c418503d30341fc6e01df7f
|
// https://github.com/XTLS/Xray-core/commit/1720be168fa069332c418503d30341fc6e01df7f
|
||||||
// https://github.com/XTLS/Xray-core/commit/0fd7691d6b28e05922d7a5a9313d97745a51ea63
|
// https://github.com/XTLS/Xray-core/commit/0fd7691d6b28e05922d7a5a9313d97745a51ea63
|
||||||
// https://github.com/XTLS/Xray-core/commit/09cc92c61d9067e0d65c1cae9124664ecfc78f43
|
// https://github.com/XTLS/Xray-core/commit/09cc92c61d9067e0d65c1cae9124664ecfc78f43
|
||||||
// https://github.com/XTLS/Xray-core/commit/7f778a4e2f123dc03fe57fbf24da59dcaf270f8a
|
// https://github.com/XTLS/Xray-core/commit/2807ee432a1fbeb301815647189eacd650b12a8b
|
||||||
package encryption
|
package encryption
|
||||||
|
|||||||
@ -24,12 +24,11 @@ type ServerSession struct {
|
|||||||
|
|
||||||
type ServerInstance struct {
|
type ServerInstance struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
nfsDKey *mlkem.DecapsulationKey768
|
nfsDKey *mlkem.DecapsulationKey768
|
||||||
nfsEKeySha256 [32]byte
|
xorKey []byte
|
||||||
xor uint32
|
minutes time.Duration
|
||||||
minutes time.Duration
|
sessions map[[21]byte]*ServerSession
|
||||||
sessions map[[21]byte]*ServerSession
|
closed bool
|
||||||
closed bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServerConn struct {
|
type ServerConn struct {
|
||||||
@ -46,10 +45,17 @@ type ServerConn struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *ServerInstance) Init(nfsDKeySeed []byte, xor uint32, minutes time.Duration) (err error) {
|
func (i *ServerInstance) Init(nfsDKeySeed []byte, xor uint32, minutes time.Duration) (err error) {
|
||||||
|
if i.nfsDKey != nil {
|
||||||
|
err = errors.New("already initialized")
|
||||||
|
return
|
||||||
|
}
|
||||||
i.nfsDKey, err = mlkem.NewDecapsulationKey768(nfsDKeySeed)
|
i.nfsDKey, err = mlkem.NewDecapsulationKey768(nfsDKeySeed)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
if xor > 0 {
|
if xor > 0 {
|
||||||
i.nfsEKeySha256 = sha256.Sum256(i.nfsDKey.EncapsulationKey().Bytes())
|
xorKey := sha256.Sum256(i.nfsDKey.EncapsulationKey().Bytes())
|
||||||
i.xor = xor
|
i.xorKey = xorKey[:]
|
||||||
}
|
}
|
||||||
if minutes > 0 {
|
if minutes > 0 {
|
||||||
i.minutes = minutes
|
i.minutes = minutes
|
||||||
@ -86,18 +92,15 @@ func (i *ServerInstance) Handshake(conn net.Conn) (net.Conn, error) {
|
|||||||
if i.nfsDKey == nil {
|
if i.nfsDKey == nil {
|
||||||
return nil, errors.New("uninitialized")
|
return nil, errors.New("uninitialized")
|
||||||
}
|
}
|
||||||
if i.xor > 0 {
|
if i.xorKey != nil {
|
||||||
conn = NewXorConn(conn, i.nfsEKeySha256[:])
|
conn = NewXorConn(conn, i.xorKey)
|
||||||
}
|
}
|
||||||
c := &ServerConn{Conn: conn}
|
c := &ServerConn{Conn: conn}
|
||||||
|
|
||||||
_, t, l, err := ReadAndDecodeHeader(c.Conn)
|
_, t, l, err := ReadAndDiscardPaddings(c.Conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if t == 23 {
|
|
||||||
return nil, errors.New("unexpected data")
|
|
||||||
}
|
|
||||||
|
|
||||||
if t == 0 {
|
if t == 0 {
|
||||||
if i.minutes == 0 {
|
if i.minutes == 0 {
|
||||||
@ -187,19 +190,9 @@ func (c *ServerConn) Read(b []byte) (int, error) {
|
|||||||
}
|
}
|
||||||
if c.peerAead == nil {
|
if c.peerAead == nil {
|
||||||
if c.peerRandom == nil { // from 1-RTT
|
if c.peerRandom == nil { // from 1-RTT
|
||||||
var t byte
|
_, t, l, err := ReadAndDiscardPaddings(c.Conn)
|
||||||
var l int
|
if err != nil {
|
||||||
var err error
|
return 0, err
|
||||||
for {
|
|
||||||
if _, t, l, err = ReadAndDecodeHeader(c.Conn); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
if t != 23 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if _, err := io.ReadFull(c.Conn, make([]byte, l)); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if t != 0 {
|
if t != 0 {
|
||||||
return 0, fmt.Errorf("unexpected type %v, expect ticket hello", t)
|
return 0, fmt.Errorf("unexpected type %v, expect ticket hello", t)
|
||||||
|
|||||||
@ -18,7 +18,7 @@ type XorConn struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewXorConn(conn net.Conn, key []byte) *XorConn {
|
func NewXorConn(conn net.Conn, key []byte) *XorConn {
|
||||||
return &XorConn{Conn: conn, key: key[:16]}
|
return &XorConn{Conn: conn, key: key}
|
||||||
//chacha20.NewUnauthenticatedCipher()
|
//chacha20.NewUnauthenticatedCipher()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user