From 83cf229909dfb8f0513db5a407abb190f60ab2c4 Mon Sep 17 00:00:00 2001 From: IconHHw <138437673+IconHHw@users.noreply.github.com> Date: Tue, 9 Jun 2026 03:55:06 +0800 Subject: [PATCH] Salamander finalmask: Replace `math/rand` with `crypto/rand` in salt generation (#6228) And https://github.com/XTLS/Xray-core/pull/6228#issuecomment-4612712100 Fixes https://github.com/XTLS/Xray-core/pull/6228#issuecomment-4599037015 --- .../internet/finalmask/salamander/salamander.go | 10 ++++------ transport/internet/finalmask/sudoku/codec.go | 12 ++++++------ .../internet/finalmask/sudoku/conn_tcp_packed.go | 2 +- transport/internet/finalmask/sudoku/table.go | 15 +++++++-------- 4 files changed, 18 insertions(+), 21 deletions(-) diff --git a/transport/internet/finalmask/salamander/salamander.go b/transport/internet/finalmask/salamander/salamander.go index d81863aa..3c7188c3 100644 --- a/transport/internet/finalmask/salamander/salamander.go +++ b/transport/internet/finalmask/salamander/salamander.go @@ -1,11 +1,11 @@ package salamander import ( + "crypto/rand" "fmt" - "math/rand" "sync" - "time" + "github.com/xtls/xray-core/common" "golang.org/x/crypto/blake2b" ) @@ -21,8 +21,7 @@ var ErrPSKTooShort = fmt.Errorf("PSK must be at least %d bytes", smPSKMinLen) // 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 + PSK []byte lk sync.Mutex keyInput []byte @@ -37,7 +36,6 @@ func NewSalamanderObfuscator(psk []byte) (*SalamanderObfuscator, error) { copy(keyInput, pskCopy) return &SalamanderObfuscator{ PSK: pskCopy, - RandSrc: rand.New(rand.NewSource(time.Now().UnixNano())), keyInput: keyInput, }, nil } @@ -47,8 +45,8 @@ func (o *SalamanderObfuscator) Obfuscate(in, out []byte) int { if len(out) < outLen { return 0 } + common.Must2(rand.Read(out[:smSaltLen])) o.lk.Lock() - _, _ = o.RandSrc.Read(out[:smSaltLen]) key := o.keyLocked(out[:smSaltLen]) o.lk.Unlock() for i, c := range in { diff --git a/transport/internet/finalmask/sudoku/codec.go b/transport/internet/finalmask/sudoku/codec.go index e748b8b7..eaf879b9 100644 --- a/transport/internet/finalmask/sudoku/codec.go +++ b/transport/internet/finalmask/sudoku/codec.go @@ -2,7 +2,7 @@ package sudoku import ( "fmt" - "math/rand" + "math/rand/v2" ) var perm4 = [24][4]byte{ @@ -67,7 +67,7 @@ func pickPaddingChance(rng *rand.Rand, pMin, pMax int) int { if pMax == pMin { return pMin } - return pMin + rng.Intn(pMax-pMin+1) + return pMin + rng.IntN(pMax-pMin+1) } func (c *codec) shouldPad() bool { @@ -77,7 +77,7 @@ func (c *codec) shouldPad() bool { if c.paddingChance >= 100 { return true } - return c.rng.Intn(100) < c.paddingChance + return c.rng.IntN(100) < c.paddingChance } func (c *codec) currentTable() *table { @@ -89,7 +89,7 @@ func (c *codec) currentTable() *table { func (c *codec) randomPadding(t *table) byte { pool := t.layout.paddingPool - return pool[c.rng.Intn(len(pool))] + return pool[c.rng.IntN(len(pool))] } func (c *codec) encode(in []byte) ([]byte, error) { @@ -112,8 +112,8 @@ func (c *codec) encode(in []byte) ([]byte, error) { return nil, fmt.Errorf("sudoku encode table missing for byte %d", b) } - hints := enc[c.rng.Intn(len(enc))] - perm := perm4[c.rng.Intn(len(perm4))] + hints := enc[c.rng.IntN(len(enc))] + perm := perm4[c.rng.IntN(len(perm4))] for _, idx := range perm { if c.shouldPad() { out = append(out, c.randomPadding(t)) diff --git a/transport/internet/finalmask/sudoku/conn_tcp_packed.go b/transport/internet/finalmask/sudoku/conn_tcp_packed.go index fa3c4c86..182e7343 100644 --- a/transport/internet/finalmask/sudoku/conn_tcp_packed.go +++ b/transport/internet/finalmask/sudoku/conn_tcp_packed.go @@ -72,7 +72,7 @@ func (e *packedEncoder) maybePad(out []byte, layout *byteLayout) []byte { return append(out, layout.paddingPool[0]) } for { - b := layout.paddingPool[e.codec.rng.Intn(len(layout.paddingPool))] + b := layout.paddingPool[e.codec.rng.IntN(len(layout.paddingPool))] if b != layout.padMarker { return append(out, b) } diff --git a/transport/internet/finalmask/sudoku/table.go b/transport/internet/finalmask/sudoku/table.go index 6396d864..464d718c 100644 --- a/transport/internet/finalmask/sudoku/table.go +++ b/transport/internet/finalmask/sudoku/table.go @@ -7,10 +7,12 @@ import ( "fmt" "math/bits" "math/rand" + rand_v2 "math/rand/v2" "sort" "strings" "sync" - "time" + + "github.com/xtls/xray-core/common" ) type table struct { @@ -570,11 +572,8 @@ func sort4(in [4]byte) [4]byte { return in } -func newSeededRand() *rand.Rand { - seed := time.Now().UnixNano() - var seedBytes [8]byte - if _, err := crypto_rand.Read(seedBytes[:]); err == nil { - seed = int64(binary.BigEndian.Uint64(seedBytes[:])) - } - return rand.New(rand.NewSource(seed)) +func newSeededRand() *rand_v2.Rand { + var seedBytes [32]byte + common.Must2(crypto_rand.Read(seedBytes[:])) + return rand_v2.New(rand_v2.NewChaCha8(seedBytes)) }