mirror of
https://github.com/apernet/hysteria.git
synced 2025-04-03 04:27:39 +03:00
77 lines
1.8 KiB
Go
77 lines
1.8 KiB
Go
package obfs
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"math/rand"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/lucas-clemente/quic-go"
|
|
)
|
|
|
|
const (
|
|
xpSaltLen = 16
|
|
udpBufferSize = 4096
|
|
)
|
|
|
|
// XPlusObfuscator obfuscates payload using one-time keys generated from hashing a pre-shared key and random salt.
|
|
// Packet format: [salt][obfuscated payload]
|
|
type XPlusObfuscator struct {
|
|
key []byte
|
|
randSrc *rand.Rand
|
|
randLk sync.Mutex
|
|
bufPool sync.Pool
|
|
saltPool sync.Pool
|
|
}
|
|
|
|
func NewXPlusObfuscator(key []byte) quic.Obfuscator {
|
|
return &XPlusObfuscator{
|
|
key: key,
|
|
randSrc: rand.New(rand.NewSource(time.Now().UnixNano())),
|
|
bufPool: sync.Pool{New: func() interface{} { return make([]byte, udpBufferSize) }},
|
|
saltPool: sync.Pool{New: func() interface{} { return make([]byte, xpSaltLen) }},
|
|
}
|
|
}
|
|
|
|
func (x *XPlusObfuscator) Obfuscate(data []byte, scat bool) ([][]byte, func()) {
|
|
if scat {
|
|
salt := x.saltPool.Get().([]byte)
|
|
x.randLk.Lock()
|
|
_, _ = x.randSrc.Read(salt)
|
|
x.randLk.Unlock()
|
|
key := sha256.Sum256(append(x.key, salt...))
|
|
buf := x.bufPool.Get().([]byte)
|
|
for i, c := range data {
|
|
buf[i] = c ^ key[i%sha256.Size]
|
|
}
|
|
payload := buf[:len(data)]
|
|
return [][]byte{salt, payload}, func() {
|
|
x.saltPool.Put(salt)
|
|
x.bufPool.Put(buf)
|
|
}
|
|
} else {
|
|
buf := x.bufPool.Get().([]byte)
|
|
x.randLk.Lock()
|
|
_, _ = x.randSrc.Read(buf[:xpSaltLen])
|
|
x.randLk.Unlock()
|
|
key := sha256.Sum256(append(x.key, buf[:xpSaltLen]...))
|
|
for i, c := range data {
|
|
buf[i+xpSaltLen] = c ^ key[i%sha256.Size]
|
|
}
|
|
payload := buf[:xpSaltLen+len(data)]
|
|
return [][]byte{payload}, func() {
|
|
x.bufPool.Put(buf)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (x *XPlusObfuscator) Deobfuscate(data []byte) int {
|
|
if len(data) <= xpSaltLen {
|
|
return 0
|
|
}
|
|
key := sha256.Sum256(append(x.key, data[:xpSaltLen]...))
|
|
for i, c := range data[xpSaltLen:] {
|
|
data[i] = c ^ key[i%sha256.Size]
|
|
}
|
|
return len(data) - xpSaltLen
|
|
}
|