Files
mihomo/transport/sudoku/init.go
2026-03-01 10:22:53 +08:00

98 lines
2.6 KiB
Go

package sudoku
import (
"encoding/hex"
"fmt"
"strings"
"github.com/metacubex/edwards25519"
"github.com/metacubex/mihomo/transport/sudoku/crypto"
"github.com/metacubex/mihomo/transport/sudoku/obfs/sudoku"
)
func NewTable(key string, tableType string) *sudoku.Table {
table, err := NewTableWithCustom(key, tableType, "")
if err != nil {
panic(fmt.Sprintf("[Sudoku] failed to init tables: %v", err))
}
return table
}
func NewTableWithCustom(key string, tableType string, customTable string) (*sudoku.Table, error) {
table, err := sudoku.NewTableWithCustom(key, tableType, customTable)
if err != nil {
return nil, err
}
return table, nil
}
// ClientAEADSeed returns a canonical "seed" that is stable between client private key material and server public key.
func ClientAEADSeed(key string) string {
key = strings.TrimSpace(key)
if key == "" {
return ""
}
b, err := hex.DecodeString(key)
if err != nil {
return key
}
// Client-side key material can be:
// - split private key: 64 bytes hex (r||k)
// - master private scalar: 32 bytes hex (x)
// - PSK string: non-hex
//
// We intentionally do NOT treat a 32-byte hex as a public key here; the client is expected
// to carry private material. Server-side should use ServerAEADSeed for public keys.
switch len(b) {
case 64:
case 32:
default:
return key
}
if recovered, err := crypto.RecoverPublicKey(key); err == nil {
return crypto.EncodePoint(recovered)
}
return key
}
// ServerAEADSeed returns a canonical seed for server-side configuration.
//
// When key is a public key (32-byte compressed point, hex), it returns the canonical point encoding.
// When key is private key material (split/master scalar), it derives and returns the public key.
func ServerAEADSeed(key string) string {
key = strings.TrimSpace(key)
if key == "" {
return ""
}
b, err := hex.DecodeString(key)
if err != nil {
return key
}
// Prefer interpreting 32-byte hex as a public key point, to avoid accidental scalar parsing.
if len(b) == 32 {
if p, err := new(edwards25519.Point).SetBytes(b); err == nil {
return hex.EncodeToString(p.Bytes())
}
}
// Fall back to client-side rules for private key materials / other formats.
return ClientAEADSeed(key)
}
// GenKeyPair generates a client "available private key" and the corresponding server public key.
func GenKeyPair() (privateKey, publicKey string, err error) {
pair, err := crypto.GenerateMasterKey()
if err != nil {
return "", "", err
}
availablePrivateKey, err := crypto.SplitPrivateKey(pair.Private)
if err != nil {
return "", "", err
}
return availablePrivateKey, crypto.EncodePoint(pair.Public), nil
}