mirror of
https://github.com/apernet/hysteria.git
synced 2025-04-03 04:27:39 +03:00
71 lines
1.5 KiB
Go
71 lines
1.5 KiB
Go
package obfs
|
|
|
|
import (
|
|
"fmt"
|
|
"math/rand"
|
|
"sync"
|
|
"time"
|
|
|
|
"golang.org/x/crypto/blake2b"
|
|
)
|
|
|
|
const (
|
|
smPSKMinLen = 4
|
|
smSaltLen = 8
|
|
smKeyLen = blake2b.Size256
|
|
)
|
|
|
|
var _ Obfuscator = (*SalamanderObfuscator)(nil)
|
|
|
|
var ErrPSKTooShort = fmt.Errorf("PSK must be at least %d bytes", smPSKMinLen)
|
|
|
|
// SalamanderObfuscator is an obfuscator that obfuscates each packet with
|
|
// the BLAKE2b-256 hash of a pre-shared key combined with a random salt.
|
|
// Packet format: [8-byte salt][payload]
|
|
type SalamanderObfuscator struct {
|
|
PSK []byte
|
|
RandSrc *rand.Rand
|
|
|
|
lk sync.Mutex
|
|
}
|
|
|
|
func NewSalamanderObfuscator(psk []byte) (*SalamanderObfuscator, error) {
|
|
if len(psk) < smPSKMinLen {
|
|
return nil, ErrPSKTooShort
|
|
}
|
|
return &SalamanderObfuscator{
|
|
PSK: psk,
|
|
RandSrc: rand.New(rand.NewSource(time.Now().UnixNano())),
|
|
}, nil
|
|
}
|
|
|
|
func (o *SalamanderObfuscator) Obfuscate(in, out []byte) int {
|
|
outLen := len(in) + smSaltLen
|
|
if len(out) < outLen {
|
|
return 0
|
|
}
|
|
o.lk.Lock()
|
|
_, _ = o.RandSrc.Read(out[:smSaltLen])
|
|
o.lk.Unlock()
|
|
key := o.key(out[:smSaltLen])
|
|
for i, c := range in {
|
|
out[i+smSaltLen] = c ^ key[i%smKeyLen]
|
|
}
|
|
return outLen
|
|
}
|
|
|
|
func (o *SalamanderObfuscator) Deobfuscate(in, out []byte) int {
|
|
outLen := len(in) - smSaltLen
|
|
if outLen <= 0 || len(out) < outLen {
|
|
return 0
|
|
}
|
|
key := o.key(in[:smSaltLen])
|
|
for i, c := range in[smSaltLen:] {
|
|
out[i] = c ^ key[i%smKeyLen]
|
|
}
|
|
return outLen
|
|
}
|
|
|
|
func (o *SalamanderObfuscator) key(salt []byte) [smKeyLen]byte {
|
|
return blake2b.Sum256(append(o.PSK, salt...))
|
|
}
|