From e5ac0805979bca71b6a0609ff33a115e350d42fd Mon Sep 17 00:00:00 2001 From: chuchur Date: Thu, 23 Apr 2026 14:49:13 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E7=9F=AD=E6=9C=9F=E5=8A=A8?= =?UTF-8?q?=E6=80=81=E5=AF=86=E7=A0=81=E7=94=9F=E6=88=90=E4=B8=8E=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E5=8A=9F=E8=83=BD=EF=BC=8C=E4=BC=98=E5=8C=96=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E4=BB=A3=E7=A0=81=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- auth.go | 3 +- qiutea.go | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++ socks.go | 6 +-- ss.go | 5 +-- totp.go | 33 +++++++++++++++ totp_test.go | 59 ++++++++++++++++++++++++++ 6 files changed, 211 insertions(+), 10 deletions(-) create mode 100644 qiutea.go create mode 100644 totp_test.go diff --git a/auth.go b/auth.go index b295267..dc02eac 100644 --- a/auth.go +++ b/auth.go @@ -36,7 +36,8 @@ func (au *LocalAuthenticator) IFAuthenticate(ip net.IP, user, password string) b } else { // if !ip.IsLoopback() && !ip.IsPrivate() { // 存的时候已经判断. secret := generateSecret(ip.String(), user) - ok, _ := verifyOTP(secret, password) + // ok, _ := verifyOTP(secret, password) + ok := VerifyShortOTP(secret, password, config.Auth.DynamicPeriod) if !ok { log.Logf("otp verify fail user=%s ip=%s pass=%s", user, ip, password) diff --git a/qiutea.go b/qiutea.go new file mode 100644 index 0000000..71ed881 --- /dev/null +++ b/qiutea.go @@ -0,0 +1,115 @@ +package gost + +const delta = 0x9E3779B9 + +func toBytes(v []uint32, includeLength bool) []byte { + length := uint32(len(v)) + n := length << 2 + if includeLength { + m := v[length-1] + n -= 4 + if (m < n-3) || (m > n) { + return nil + } + n = m + } + bytes := make([]byte, n) + for i := uint32(0); i < n; i++ { + bytes[i] = byte(v[i>>2] >> ((i & 3) << 3)) + } + return bytes +} + +func toUint32s(bytes []byte, includeLength bool) (v []uint32) { + length := uint32(len(bytes)) + n := length >> 2 + if length&3 != 0 { + n++ + } + if includeLength { + v = make([]uint32, n+1) + v[n] = length + } else { + v = make([]uint32, n) + } + for i := uint32(0); i < length; i++ { + v[i>>2] |= uint32(bytes[i]) << ((i & 3) << 3) + } + return v +} + +func mx(sum uint32, y uint32, z uint32, p uint32, e uint32, k []uint32) uint32 { + return ((z>>5 ^ y<<2) + (y>>3 ^ z<<4)) ^ ((sum ^ y) + (k[p&3^e] ^ z)) +} + +func fixk(k []uint32) []uint32 { + if len(k) < 4 { + key := make([]uint32, 4) + copy(key, k) + return key + } + return k +} + +func encrypt(v []uint32, k []uint32) []uint32 { + length := uint32(len(v)) + n := length - 1 + k = fixk(k) + var y, z, sum, e, p, q uint32 + z = v[n] + sum = 0 + for q = 6 + 52/length; q > 0; q-- { + sum += delta + e = sum >> 2 & 3 + for p = 0; p < n; p++ { + y = v[p+1] + v[p] += mx(sum, y, z, p, e, k) + z = v[p] + } + y = v[0] + v[n] += mx(sum, y, z, p, e, k) + z = v[n] + } + return v +} + +func decrypt(v []uint32, k []uint32) []uint32 { + length := uint32(len(v)) + n := length - 1 + k = fixk(k) + var y, z, sum, e, p, q uint32 + y = v[0] + q = 6 + 52/length + for sum = q * delta; sum != 0; sum -= delta { + e = sum >> 2 & 3 + for p = n; p > 0; p-- { + z = v[p-1] + v[p] -= mx(sum, y, z, p, e, k) + y = v[p] + } + z = v[n] + v[0] -= mx(sum, y, z, p, e, k) + y = v[0] + } + return v +} + +// Encrypt the data with key. +// data is the bytes to be encrypted. +// key is the encrypt key. It is the same as the decrypt key. +func Encrypt(data []byte, key []byte) []byte { + if len(data) == 0 { + return data + } + return toBytes(encrypt(toUint32s(data, true), toUint32s(key, false)), false) +} + +// Decrypt the data with key. +// data is the bytes to be decrypted. +// key is the decrypted key. It is the same as the encrypt key. +func Decrypt(data []byte, key []byte) []byte { + if len(data) == 0 { + return data + } + return toBytes(decrypt(toUint32s(data, false), toUint32s(key, false)), true) +} diff --git a/socks.go b/socks.go index eb2bc50..123aace 100644 --- a/socks.go +++ b/socks.go @@ -1314,11 +1314,7 @@ func (h *socks5Handler) transportUDP(relay, peer net.PacketConn) (err error) { } }() - select { - case err = <-errc: - //log.Println("w exit", err) - } - + err = <-errc return } diff --git a/ss.go b/ss.go index f4831f7..d056ae2 100644 --- a/ss.go +++ b/ss.go @@ -410,10 +410,7 @@ func (h *shadowUDPHandler) transportPacket(conn, cc net.PacketConn) (err error) } }() - select { - case err = <-errc: - } - + err = <-errc return } diff --git a/totp.go b/totp.go index c78a9a2..9a5ed9c 100644 --- a/totp.go +++ b/totp.go @@ -7,6 +7,7 @@ import ( "encoding/binary" "encoding/hex" "fmt" + "math/rand" "time" ) @@ -65,3 +66,35 @@ func GeneratePassword(ip, user string) string { hashedSrcHex := hex.EncodeToString(hashedSrc) return hashedSrcHex } + +func GenerateShortOTP(key string) string { + data := make([]byte, 8) + binary.BigEndian.PutUint32(data[:4], rand.Uint32()) + binary.BigEndian.PutUint32(data[4:], uint32(time.Now().Unix())) + + encryptData := Encrypt(data, []byte(key)) + + return fmt.Sprintf("%x", encryptData) +} + +func VerifyShortOTP(key string, otp string, maxAge int64) bool { + var encryptData []byte + _, err := fmt.Sscanf(otp, "%x", &encryptData) + if err != nil || len(encryptData) == 0 { + return false + } + + decryptData := Decrypt(encryptData, []byte(key)) + if len(decryptData) != 8 { + return false + } + + timestamp := int64(binary.BigEndian.Uint32(decryptData[4:])) + + now := time.Now().Unix() + if now-timestamp > maxAge || timestamp > now+5 { + return false + } + + return true +} diff --git a/totp_test.go b/totp_test.go new file mode 100644 index 0000000..b07e75c --- /dev/null +++ b/totp_test.go @@ -0,0 +1,59 @@ +package gost + +import ( + "testing" + "time" +) + +func TestQiuTea(t *testing.T) { + + var secret = "abcdefg" + + startSec := 0 + passkey := GenerateShortOTP(secret) + println("password:", passkey) + for { + println("password:", passkey) + startSec++ + time.Sleep(1 * time.Second) + + valid := VerifyShortOTP(secret, passkey, 40) + println("times:", startSec) + if !valid { + println(" false") + break + } + } +} + +func TestQiuTea2(t *testing.T) { + + secret := generateSecret("192.168.1.1", "user") + + for { + passkey := GenerateShortOTP(secret) + + println("secret: ", secret) + println("password:", passkey) + time.Sleep(1 * time.Second) + } +} + +func TestQiuTea3(t *testing.T) { + + password := "8b0775013ae1e3714914c9e6" + secret := "c00cd5a1f706b614c7e4882ff7ea6d535971e685b8d75741b446f05d28db3447" + startSec := 0 + for { + println("password:", password) + startSec++ + time.Sleep(1 * time.Second) + + valid := VerifyShortOTP(secret, password, 20) + println("times:", startSec) + if !valid { + println(" false") + break + } + } +}