From 48883b07835e0f1343930bd9cd1ef372c6dbae99 Mon Sep 17 00:00:00 2001 From: wweir Date: Wed, 5 Aug 2026 14:04:59 +0800 Subject: [PATCH] sec(sower): strengthen auth checksum against brute force sumChecksum used binary.Uvarint over the digest, which stops at the first byte with a clear continuation bit: ~50% of checksums collapsed to 7 bits of entropy (~15 bits effective), making the auth check brute-forceable. Take a fixed 64-bit window of a SHA-256 digest instead. Wire layout is unchanged (checksum stays 8 bytes), and the randomized field also removes the "high bytes all zero" fingerprint. --- transport/sower/sower.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/transport/sower/sower.go b/transport/sower/sower.go index 7ca6d05..c29ef39 100644 --- a/transport/sower/sower.go +++ b/transport/sower/sower.go @@ -2,7 +2,7 @@ package sower import ( "bytes" - "crypto/md5" + "crypto/sha256" "encoding/binary" "fmt" "io" @@ -93,11 +93,14 @@ func (s *Sower) Wrap(conn net.Conn, tgtHost string, tgtPort uint16) error { } func sumChecksum(target [maxDomainLength]byte, password []byte) uint64 { - h := md5.New() + h := sha256.New() h.Write(target[:]) h.Write(password) - var checksum [md5.Size]byte + var checksum [sha256.Size]byte h.Sum(checksum[:0]) - checksumVal, _ := binary.Uvarint(checksum[:]) - return checksumVal + // Take a fixed 64-bit window of the digest. binary.Uvarint would only + // consume bytes until the first continuation bit is clear (typically the + // first byte, ~50% of the time), collapsing the checksum to 7 bits of + // entropy and making the auth check brute-forceable. + return binary.BigEndian.Uint64(checksum[:8]) }