mirror of https://github.com/XTLS/Xray-core
94 lines
1.9 KiB
Go
94 lines
1.9 KiB
Go
package encryption
|
|
|
|
import (
|
|
"crypto/aes"
|
|
"crypto/cipher"
|
|
"net"
|
|
|
|
"lukechampine.com/blake3"
|
|
)
|
|
|
|
func NewCTR(key, iv []byte) cipher.Stream {
|
|
k := make([]byte, 32)
|
|
blake3.DeriveKey(k, "VLESS", key) // avoids using key directly
|
|
block, _ := aes.NewCipher(k)
|
|
return cipher.NewCTR(block, iv)
|
|
//chacha20.NewUnauthenticatedCipher()
|
|
}
|
|
|
|
type XorConn struct {
|
|
net.Conn
|
|
CTR cipher.Stream
|
|
PeerCTR cipher.Stream
|
|
OutSkip int
|
|
OutHeader []byte
|
|
InSkip int
|
|
InHeader []byte
|
|
}
|
|
|
|
func NewXorConn(conn net.Conn, ctr, peerCTR cipher.Stream, outSkip, inSkip int) *XorConn {
|
|
return &XorConn{
|
|
Conn: conn,
|
|
CTR: ctr,
|
|
PeerCTR: peerCTR,
|
|
OutSkip: outSkip,
|
|
OutHeader: make([]byte, 0, 5), // important
|
|
InSkip: inSkip,
|
|
InHeader: make([]byte, 0, 5), // important
|
|
}
|
|
}
|
|
|
|
func (c *XorConn) Write(b []byte) (int, error) {
|
|
if len(b) == 0 {
|
|
return 0, nil
|
|
}
|
|
for p := b; ; {
|
|
if len(p) <= c.OutSkip {
|
|
c.OutSkip -= len(p)
|
|
break
|
|
}
|
|
p = p[c.OutSkip:]
|
|
c.OutSkip = 0
|
|
need := 5 - len(c.OutHeader)
|
|
if len(p) < need {
|
|
c.OutHeader = append(c.OutHeader, p...)
|
|
c.CTR.XORKeyStream(p, p)
|
|
break
|
|
}
|
|
c.OutSkip, _ = DecodeHeader(append(c.OutHeader, p[:need]...))
|
|
c.OutHeader = c.OutHeader[:0]
|
|
c.CTR.XORKeyStream(p[:need], p[:need])
|
|
p = p[need:]
|
|
}
|
|
if _, err := c.Conn.Write(b); err != nil {
|
|
return 0, err
|
|
}
|
|
return len(b), nil
|
|
}
|
|
|
|
func (c *XorConn) Read(b []byte) (int, error) {
|
|
if len(b) == 0 {
|
|
return 0, nil
|
|
}
|
|
n, err := c.Conn.Read(b)
|
|
for p := b[:n]; ; {
|
|
if len(p) <= c.InSkip {
|
|
c.InSkip -= len(p)
|
|
break
|
|
}
|
|
p = p[c.InSkip:]
|
|
c.InSkip = 0
|
|
need := 5 - len(c.InHeader)
|
|
if len(p) < need {
|
|
c.PeerCTR.XORKeyStream(p, p)
|
|
c.InHeader = append(c.InHeader, p...)
|
|
break
|
|
}
|
|
c.PeerCTR.XORKeyStream(p[:need], p[:need])
|
|
c.InSkip, _ = DecodeHeader(append(c.InHeader, p[:need]...))
|
|
c.InHeader = c.InHeader[:0]
|
|
p = p[need:]
|
|
}
|
|
return n, err
|
|
}
|