onion

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 18, 2026 License: MIT Imports: 26 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BlindPublicKey

func BlindPublicKey(pubkey [32]byte, periodNumber int64, periodLength int64) ([32]byte, error)

BlindPublicKey derives the blinded public key A' = h * A for the given time period. The nonce N = "key-blind" | INT_8(period_number) | INT_8(period_length).

func BuildRendLinkSpecs

func BuildRendLinkSpecs(identity [20]byte, address string, orPort uint16, ed25519ID [32]byte) ([]byte, error)

BuildRendLinkSpecs encodes link specifiers for a rendezvous point in the format expected by INTRODUCE1 plaintext: NSPEC | (LSTYPE | LSLEN | LSPEC)...

func ConnectOnionService

func ConnectOnionService(
	address string,
	port uint16,
	consensus *directory.Consensus,
	httpClient *http.Client,
	builder CircuitBuilder,
	logger *slog.Logger,
) (io.ReadWriteCloser, error)

ConnectOnionService performs the full v3 onion service connection protocol: resolve descriptor, establish rendezvous, introduce, and complete handshake. Returns an io.ReadWriteCloser for the connected stream.

func CurrentTimePeriod

func CurrentTimePeriod() int64

CurrentTimePeriod computes the time period from the current time. Prefer TimePeriodFromConsensus when a consensus is available.

func DecodeOnion

func DecodeOnion(address string) ([32]byte, error)

DecodeOnion decodes a v3 .onion address and returns the 32-byte Ed25519 public key. It validates the checksum, version byte, and rejects keys with torsion components.

func DecryptDescriptorLayer

func DecryptDescriptorLayer(encrypted []byte, secretData, subcredential []byte, revisionCounter uint64, stringConstant string) ([]byte, error)

DecryptDescriptorLayer decrypts one layer of a v3 HS descriptor. The encrypted blob format is: SALT(16) | ENCRYPTED(variable) | MAC(32)

Parameters:

  • encrypted: the raw encrypted blob
  • secretData: SECRET_DATA (blinded_public_key for outer, blinded_public_key|descriptor_cookie for inner)
  • subcredential: the 32-byte subcredential
  • revisionCounter: the descriptor's revision counter
  • stringConstant: "hsdir-superencrypted-data" for outer, "hsdir-encrypted-data" for inner

func FetchDescriptor

func FetchDescriptor(client *http.Client, hsdirAddr string, blindedKey [32]byte) (string, error)

FetchDescriptor fetches a v3 hidden service descriptor from the given HSDir relay. The request is made to the relay's DirPort using the blinded public key to construct the URL: /tor/hs/3/<base64_blinded_key>

Per rend-spec-v3, this request should be made anonymously over a Tor circuit. The client parameter allows routing through Tor.

func FetchDescriptorViaCircuit

func FetchDescriptorViaCircuit(circ *circuit.Circuit, blindedKey [32]byte) (string, error)

FetchDescriptorViaCircuit fetches a v3 hidden service descriptor using BEGIN_DIR over an existing circuit (for HSDirs without a public DirPort). The circuit's last hop must be the HSDir relay.

func GenerateRendezvousCookie

func GenerateRendezvousCookie() ([20]byte, error)

GenerateRendezvousCookie generates a random 20-byte rendezvous cookie.

func GetSRVForClient

func GetSRVForClient(consensus *directory.Consensus) ([]byte, error)

GetSRVForClient returns the appropriate SRV for a client to use, per rend-spec-v3 §2.2.4.1. Between a new TP and a new SRV, use current SRV. Between a new SRV and a new TP, use previous SRV.

func HsNtorClientCompleteHandshake

func HsNtorClientCompleteHandshake(state *HsNtorClientState, serverPK [32]byte, auth [32]byte) ([]byte, error)

HsNtorClientCompleteHandshake completes the client side of the hs-ntor handshake upon receiving the RENDEZVOUS2 message containing SERVER_PK (Y) and AUTH. Returns the key seed for key expansion.

func HsNtorExpandKeys

func HsNtorExpandKeys(ntorKeySeed []byte) (df, db [32]byte, kf, kb [32]byte)

HsNtorExpandKeys derives the relay encryption keys from the NTOR_KEY_SEED. K = KDF(NTOR_KEY_SEED | m_hsexpand, SHA3_256_LEN*2 + S_KEY_LEN*2) Returns Df(32), Db(32), Kf(32), Kb(32).

func IsOnionAddress

func IsOnionAddress(target string) bool

IsOnionAddress returns true if the target address is a .onion address.

func NewRendezvousDigests

func NewRendezvousDigests(df, db [32]byte) (hashDf, hashDb sha3Hash)

NewRendezvousDigests creates SHA3-256 running digests initialized with the given seeds. These are used for relay cell authentication on the onion service circuit (as opposed to SHA-1 for regular circuit hops).

func PickRandomHSDir

func PickRandomHSDir(candidates []*directory.Relay) (*directory.Relay, error)

PickRandomHSDir picks a random HSDir from the candidate list.

func SelectHSDirs

func SelectHSDirs(consensus *directory.Consensus, blindedKey [32]byte, periodNum, periodLength int64, srv []byte) ([]*directory.Relay, error)

SelectHSDirs selects the HSDirs to fetch a descriptor from for the given blinded public key and time period, per rend-spec-v3 §2.2.3.

func Subcredential

func Subcredential(pubkey [32]byte, blindedKey [32]byte) [32]byte

Subcredential computes the subcredential for a given time period. N_hs_subcred = SHA3-256("subcredential" | N_hs_cred | blinded_public_key) N_hs_cred = SHA3-256("credential" | public_identity_key)

func TimePeriod

func TimePeriod(t time.Time, periodLength int64) int64

TimePeriod computes the current time period number. tp = (minutes_since_epoch - rotation_time_offset) / time_period_length

func TimePeriodFromConsensus

func TimePeriodFromConsensus(consensus *directory.Consensus) int64

TimePeriodFromConsensus computes the time period number using the consensus valid-after time (not the system clock), per rend-spec-v3.

Types

type BuiltCircuit

type BuiltCircuit struct {
	Circuit    *circuit.Circuit
	LinkCloser io.Closer             // Closes the underlying TLS link
	LastHop    *descriptor.RelayInfo // Info about the last relay in the circuit
}

BuiltCircuit holds a circuit and the metadata about the last hop, needed for the onion service protocol.

type CircuitBuilder

type CircuitBuilder interface {
	// BuildCircuit builds a 3-hop circuit. If target is non-nil, it is used
	// as the last hop instead of a randomly selected exit.
	BuildCircuit(target *descriptor.RelayInfo) (*BuiltCircuit, error)
}

CircuitBuilder abstracts the ability to build a 3-hop Tor circuit.

type ConnectResult

type ConnectResult struct {
	IntroPoints []IntroPoint
	BlindedKey  [32]byte
	Subcred     [32]byte
	Descriptor  *DescriptorOuter
}

ConnectResult holds the information needed to establish a stream to an onion service after the introduction/rendezvous protocol completes.

func ResolveOnionService

func ResolveOnionService(address string, consensus *directory.Consensus, httpClient *http.Client, builder ...CircuitBuilder) (*ConnectResult, error)

ResolveOnionService resolves a .onion address to a set of introduction points by fetching and decrypting the service descriptor. This is the first step before the introduction/rendezvous protocol.

Parameters:

  • address: the v3 .onion address (with or without .onion suffix)
  • consensus: the current consensus
  • httpClient: HTTP client for fetching the descriptor (can be nil if builder is provided)
  • builder: optional circuit builder for BEGIN_DIR fetch (used when DirPort=0)

type DescriptorOuter

type DescriptorOuter struct {
	LifetimeSeconds int
	SigningKeyCert  []byte // The signing key certificate
	RevisionCounter uint64
	Superencrypted  []byte // The superencrypted blob
	Signature       []byte
}

ParseDescriptorOuterLayer parses the outer layer of a v3 HS descriptor, returning the fields needed for decryption.

func ParseDescriptorOuter

func ParseDescriptorOuter(text string) (*DescriptorOuter, error)

ParseDescriptorOuter parses the outer plaintext layer of an HS descriptor.

type HsNtorClientState

type HsNtorClientState struct {
	X [32]byte // Client ephemeral public key

	B       [32]byte // Service encryption key (KP_hss_ntor / enc-key ntor)
	AuthKey []byte   // Introduction point auth key
	Subcred [32]byte // Subcredential
	// contains filtered or unexported fields
}

HsNtorClientState holds the client's ephemeral state during an hs-ntor handshake.

func BuildINTRODUCE1

func BuildINTRODUCE1(authKey []byte, encKey [32]byte, subcredential [32]byte,
	rendCookie [20]byte, rendNodeOnionKey [32]byte, rendLinkSpecs []byte) ([]byte, *HsNtorClientState, error)

BuildINTRODUCE1 builds the INTRODUCE1 relay cell payload. Parameters:

  • authKey: the introduction point's auth key (from descriptor)
  • encKey: the service's enc-key ntor (curve25519, from descriptor)
  • subcredential: the service's subcredential
  • rendCookie: 20-byte rendezvous cookie
  • rendNodeOnionKey: the rendezvous point's ntor onion key
  • rendLinkSpecs: the rendezvous point's link specifiers (encoded for EXTEND2)

Returns the full INTRODUCE1 payload and the hs-ntor client state for completing the handshake when RENDEZVOUS2 arrives.

func HsNtorClientHandshake

func HsNtorClientHandshake(B [32]byte, authKey []byte, subcredential [32]byte) (*HsNtorClientState, [32]byte, [32]byte, error)

HsNtorClientHandshake initiates the client side of an hs-ntor handshake. It generates the ephemeral keypair, derives the encryption and MAC keys for the INTRODUCE1 encrypted section, and returns the client state.

B is the service's enc-key (curve25519 public key from the descriptor). authKey is the introduction point's auth key. subcredential is the service's subcredential for the current period.

type IntroPoint

type IntroPoint struct {
	// LinkSpecifiers is the raw link specifiers block for use in EXTEND2.
	LinkSpecifiers []byte
	// OnionKey is the ntor onion key of the introduction point relay (curve25519).
	OnionKey [32]byte
	// AuthKeyCert is the raw auth-key certificate.
	AuthKeyCert []byte
	// AuthKey is the 32-byte Ed25519 auth key extracted from the certificate.
	AuthKey [32]byte
	// EncKey is the curve25519 encryption key for the hs-ntor handshake (KP_hss_ntor).
	EncKey [32]byte
	// EncKeyCert is the raw enc-key-cert certificate.
	EncKeyCert []byte
}

IntroPoint represents a parsed introduction point from a v3 HS descriptor.

func DecryptAndParseDescriptor

func DecryptAndParseDescriptor(outer *DescriptorOuter, blindedKey [32]byte, subcredential [32]byte) ([]IntroPoint, error)

DecryptAndParseDescriptor decrypts both layers of a v3 HS descriptor and returns the list of introduction points.

type ParsedLinkSpecs

type ParsedLinkSpecs struct {
	Address    string // IPv4 or IPv6 address
	ORPort     uint16
	Identity   [20]byte // RSA identity (SHA-1 fingerprint)
	Ed25519ID  [32]byte
	HasEd25519 bool
}

ParsedLinkSpecs holds the extracted fields from link specifiers.

func ParseLinkSpecifiers

func ParseLinkSpecifiers(data []byte) (*ParsedLinkSpecs, error)

ParseLinkSpecifiers parses the NSPEC-prefixed link specifier block (as stored in IntroPoint.LinkSpecifiers) into structured fields.

type RendezvousKeys

type RendezvousKeys struct {
	Df [32]byte // Forward digest seed (SHA3-256)
	Db [32]byte // Backward digest seed (SHA3-256)
	Kf [32]byte // Forward AES-256-CTR key
	Kb [32]byte // Backward AES-256-CTR key
}

RendezvousKeys holds the derived keys for an onion service circuit.

func CompleteRendezvous

func CompleteRendezvous(state *HsNtorClientState, rendezvous2Body []byte) (*RendezvousKeys, error)

CompleteRendezvous processes the RENDEZVOUS2 message from the rendezvous point, completing the hs-ntor handshake and deriving circuit keys. The rendezvous2Body contains: SERVER_PK(32) | AUTH(32).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL