diff --git a/proxy/shadowsocks/config.go b/proxy/shadowsocks/config.go index 4138b1141..86dd47141 100644 --- a/proxy/shadowsocks/config.go +++ b/proxy/shadowsocks/config.go @@ -25,6 +25,8 @@ type MemoryAccount struct { Key []byte replayFilter antireplay.GeneralizedReplayFilter + + ReducedIVEntropy bool } // Equals implements protocol.Account.Equals(). @@ -101,6 +103,7 @@ func (a *Account) AsAccount() (protocol.Account, error) { } return nil }(), + ReducedIVEntropy: a.ExperimentReducedInitialIvEntropy, }, nil } diff --git a/proxy/shadowsocks/protocol.go b/proxy/shadowsocks/protocol.go index 55549d907..6ae8f4f80 100644 --- a/proxy/shadowsocks/protocol.go +++ b/proxy/shadowsocks/protocol.go @@ -6,6 +6,7 @@ import ( "crypto/sha256" "hash/crc32" "io" + mrand "math/rand" gonet "net" "github.com/v2fly/v2ray-core/v5/common" @@ -103,6 +104,9 @@ func WriteTCPRequest(request *protocol.RequestHeader, writer io.Writer) (buf.Wri if account.Cipher.IVSize() > 0 { iv = make([]byte, account.Cipher.IVSize()) common.Must2(rand.Read(iv)) + if account.ReducedIVEntropy { + remapToPrintable(iv[:6]) + } if ivError := account.CheckIV(iv); ivError != nil { return nil, newError("failed to mark outgoing iv").Base(ivError) } @@ -301,3 +305,11 @@ func (w *UDPWriter) WriteTo(payload []byte, addr gonet.Addr) (n int, err error) packet.Release() return len(payload), err } + +func remapToPrintable(input []byte) { + const charSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&()*+,./:;<=>?@[]^_`{|}~\\\"" + seed := mrand.New(mrand.NewSource(int64(crc32.ChecksumIEEE(input)))) + for i := range input { + input[i] = charSet[seed.Intn(len(charSet))] + } +}