diff --git a/utils/tor.go b/utils/tor.go index 7174d1a..9261383 100644 --- a/utils/tor.go +++ b/utils/tor.go @@ -33,6 +33,8 @@ func expandKey(pri ed25519.PrivateKey) string { return base64.StdEncoding.EncodeToString(h[:]) } +const V3HostnameLength = 56 + // Hidden service version const version = byte(0x03) @@ -48,6 +50,7 @@ func getCheckdigits(pub ed25519.PublicKey) []byte { return checksum[:2] } +// GetTorV3Hostname converts an ed25519 public key to a valid tor onion hostname func GetTorV3Hostname(pub ed25519.PublicKey) string { // Construct onion address base32(publicKey || checkdigits || version) checkdigits := getCheckdigits(pub) @@ -57,3 +60,17 @@ func GetTorV3Hostname(pub ed25519.PublicKey) string { serviceID := base32.StdEncoding.EncodeToString(combined) return strings.ToLower(serviceID) } + +// IsValidHostname returns true if the given address is a valid onion v3 address +func IsValidHostname(address string) bool { + if len(address) == V3HostnameLength { + data, err := base32.StdEncoding.DecodeString(strings.ToUpper(address)) + if err ==nil { + pubkey := data[0:ed25519.PublicKeySize] + if GetTorV3Hostname(ed25519.PublicKey(pubkey)) == address { + return true + } + } + } + return false +} \ No newline at end of file diff --git a/utils/tor_test.go b/utils/tor_test.go index 717cb44..e1d9f22 100644 --- a/utils/tor_test.go +++ b/utils/tor_test.go @@ -1,10 +1,12 @@ package utils import ( + "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/asn1" "encoding/pem" + "golang.org/x/crypto/ed25519" "testing" ) @@ -41,3 +43,16 @@ func TestGetTorHostname(t *testing.T) { t.Errorf("Hostname %s does not equal %s", hostname, "kwke2hntvyfqm7dr") } } + + +func TestV3(t *testing.T) { + pub,_,_ := ed25519.GenerateKey(rand.Reader) + hostname := GetTorV3Hostname(pub) + if !IsValidHostname(hostname) { + t.Errorf("Generated V3 Hostname was invalid") + } + + if IsValidHostname(hostname[0:34]) { + t.Errorf("Invalid V3 Hostname was marked valid") + } +} \ No newline at end of file