Stem Docs

Hidden Service Descriptor

Hidden Service Descriptor

Parsing for Tor hidden service descriptors as described in Tor's version 2 and version 3 rend-spec.

Unlike other descriptor types these describe a hidden service rather than a relay. They're created by the service, and can only be fetched via relays with the HSDir flag.

These are only available through the Controller's get_hidden_service_descriptor() method.

Module Overview:

BaseHiddenServiceDescriptor - Common parent for hidden service descriptors
  |- HiddenServiceDescriptorV2 - Version 2 hidden service descriptor
  +- HiddenServiceDescriptorV3 - Version 3 hidden service descriptor
       |- address_from_identity_key - convert an identity key to address
       |- identity_key_from_address - convert an address to identity key
       +- decrypt - decrypt and parse encrypted layers

OuterLayer - First encrypted layer of a hidden service v3 descriptor
InnerLayer - Second encrypted layer of a hidden service v3 descriptor

New in version 1.4.0.

exception stem.descriptor.hidden_service.DecryptionFailure[source]

Bases: exceptions.Exception

Failure to decrypt the hidden service descriptor's introduction-points.

class stem.descriptor.hidden_service.IntroductionPoints[source]

Bases: stem.descriptor.hidden_service.IntroductionPoints

Introduction point for a v2 hidden service.

Variables:
  • identifier (str) -- hash of this introduction point's identity key
  • address (str) -- address of this introduction point
  • port (int) -- port where this introduction point is listening
  • onion_key (str) -- public key for communicating with this introduction point
  • service_key (str) -- public key for communicating with this hidden service
  • intro_authentication (list) -- tuples of the form (auth_type, auth_data) for establishing a connection
class stem.descriptor.hidden_service.IntroductionPointV3[source]

Bases: stem.descriptor.hidden_service.IntroductionPointV3

Introduction point for a v3 hidden service.

New in version 1.8.0.

Variables:
  • link_specifiers (list) -- LinkSpecifier where this service is reachable
  • onion_key_raw (unicode) -- base64 ntor introduction point public key
  • auth_key_cert (stem.descriptor.certificate.Ed25519Certificate) -- cross-certifier of the signing key with the auth key
  • enc_key_raw (unicode) -- base64 introduction request encryption key
  • enc_key_cert (stem.descriptor.certificate.Ed25519Certificate) -- cross-certifier of the signing key by the encryption key
  • legacy_key_raw (str) -- base64 legacy introduction point RSA public key
  • legacy_key_cert (str) -- base64 cross-certifier of the signing key by the legacy key
static parse(content)[source]

Parses an introduction point from its descriptor content.

Parameters:content (str) -- descriptor content to parse
Returns:IntroductionPointV3 for the descriptor content
Raises :ValueError if descriptor content is malformed
static create_for_address(address, port, expiration=None, onion_key=None, enc_key=None, auth_key=None, signing_key=None)[source]

Simplified constructor for a single address/port link specifier.

Parameters:
  • address (str) -- IPv4 or IPv6 address where the service is reachable
  • port (int) -- port where the service is reachable
  • expiration (datetime.datetime) -- when certificates should expire
  • onion_key (str) -- encoded, X25519PublicKey, or X25519PrivateKey onion key
  • enc_key (str) -- encoded, X25519PublicKey, or X25519PrivateKey encryption key
  • auth_key (str) -- encoded, Ed25519PublicKey, or Ed25519PrivateKey authentication key
  • signing_key (cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey) -- service signing key
Returns:

IntroductionPointV3 with these attributes

Raises :

ValueError if the address, port, or keys are malformed

Simplified constructor. For more sophisticated use cases you can use this as a template for how introduction points are properly created.

Parameters:
  • link_specifiers (list) -- series of stem.client.datatype.LinkSpecifier where the service is reachable
  • expiration (datetime.datetime) -- when certificates should expire
  • onion_key (str) -- encoded, X25519PublicKey, or X25519PrivateKey onion key
  • enc_key (str) -- encoded, X25519PublicKey, or X25519PrivateKey encryption key
  • auth_key (str) -- encoded, Ed25519PublicKey, or Ed25519PrivateKey authentication key
  • signing_key (cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey) -- service signing key
Returns:

IntroductionPointV3 with these attributes

Raises :

ValueError if the address, port, or keys are malformed

encode()[source]

Descriptor representation of this introduction point.

Returns:str for our descriptor representation
onion_key()[source]

Provides our ntor introduction point public key.

Returns:

ntor X25519PublicKey

Raises :
  • ImportError if required the cryptography module is unavailable
  • EnvironmentError if OpenSSL x25519 unsupported
auth_key()[source]

Provides our authentication certificate's public key.

Returns:

Ed25519PublicKey

Raises :
  • ImportError if required the cryptography module is unavailable
  • EnvironmentError if OpenSSL x25519 unsupported
enc_key()[source]

Provides our encryption key.

Returns:

encryption X25519PublicKey

Raises :
  • ImportError if required the cryptography module is unavailable
  • EnvironmentError if OpenSSL x25519 unsupported
legacy_key()[source]

Provides our legacy introduction point public key.

Returns:

legacy X25519PublicKey

Raises :
  • ImportError if required the cryptography module is unavailable
  • EnvironmentError if OpenSSL x25519 unsupported
class stem.descriptor.hidden_service.AuthorizedClient(id=None, iv=None, cookie=None)[source]

Bases: object

Client authorized to use a v3 hidden service.

New in version 1.8.0.

Variables:
  • id (str) -- base64 encoded client id
  • iv (str) -- base64 encoded randomized initialization vector
  • cookie (str) -- base64 encoded authentication cookie
class stem.descriptor.hidden_service.BaseHiddenServiceDescriptor(contents, lazy_load=False)[source]

Bases: stem.descriptor.Descriptor

Hidden service descriptor.

New in version 1.8.0.

class stem.descriptor.hidden_service.HiddenServiceDescriptorV2(raw_contents, validate=False, skip_crypto_validation=False)[source]

Bases: stem.descriptor.hidden_service.BaseHiddenServiceDescriptor

Version 2 hidden service descriptor.

Variables:
  • descriptor_id (str) -- * identifier for this descriptor, this is a base32 hash of several fields
  • version (int) -- * hidden service descriptor version
  • permanent_key (str) -- * long term key of the hidden service
  • secret_id_part (str) -- * hash of the time period, cookie, and replica values so our descriptor_id can be validated
  • published (datetime) -- * time in UTC when this descriptor was made
  • protocol_versions (list) -- * list of int versions that are supported when establishing a connection
  • introduction_points_encoded (str) -- raw introduction points blob
  • introduction_points_auth (list) -- * tuples of the form (auth_method, auth_data) for our introduction_points_content (deprecated, always [])
  • introduction_points_content (bytes) -- decoded introduction-points content without authentication data, if using cookie authentication this is encrypted
  • signature (str) -- signature of the descriptor content

* attribute is either required when we're parsed with validation or has a default value, others are left as None if undefined

Changed in version 1.6.0: Moved from the deprecated pycrypto module to cryptography for validating signatures.

Changed in version 1.6.0: Added the skip_crypto_validation constructor argument.

TYPE_ANNOTATION_NAME = 'hidden-service-descriptor'
classmethod content(attr=None, exclude=(), sign=False)[source]
classmethod create(attr=None, exclude=(), validate=True, sign=False)[source]
introduction_points(*args, **kwds)[source]

Provided this service's introduction points.

Returns:

list of IntroductionPoints

Raises :
  • ValueError if the our introduction-points is malformed
  • DecryptionFailure if unable to decrypt this field
class stem.descriptor.hidden_service.HiddenServiceDescriptorV3(raw_contents, validate=False)[source]

Bases: stem.descriptor.hidden_service.BaseHiddenServiceDescriptor

Version 3 hidden service descriptor.

Variables:
  • version (int) -- * hidden service descriptor version
  • lifetime (int) -- * minutes after publication this descriptor is valid
  • signing_cert (stem.descriptor.certificate.Ed25519Certificate) -- * cross-certifier for the short-term descriptor signing key
  • revision_counter (int) -- * descriptor revision number
  • superencrypted (str) -- * encrypted HS-DESC-ENC payload
  • signature (str) -- * signature of this descriptor

* attribute is either required when we're parsed with validation or has a default value, others are left as None if undefined

New in version 1.8.0.

TYPE_ANNOTATION_NAME = 'hidden-service-descriptor-3'
classmethod content(attr=None, exclude=(), sign=False, inner_layer=None, outer_layer=None, identity_key=None, signing_key=None, signing_cert=None, revision_counter=None, blinding_nonce=None)[source]

Hidden service v3 descriptors consist of three parts:

  • InnerLayer, which most notably contain introduction points where the service can be reached.
  • OuterLayer, which encrypts the InnerLayer among other paremters.
  • HiddenServiceDescriptorV3, which contains the OuterLayer and plaintext parameters.

Construction through this method can supply any or none of these, with omitted parameters populated with randomized defaults.

Ed25519 key blinding adds an additional ~20 ms, and as such is disabled by default. To blind with a random nonce simply call...

HiddenServiceDescriptorV3.create(blinding_nonce = os.urandom(32))
Parameters:
  • attr (dict) -- keyword/value mappings to be included in plaintext descriptor
  • exclude (list) -- mandatory keywords to exclude from the descriptor, this results in an invalid descriptor
  • sign (bool) -- includes cryptographic signatures and digests if True
  • inner_layer (stem.descriptor.hidden_service.InnerLayer) -- inner encrypted layer
  • outer_layer (stem.descriptor.hidden_service.OuterLayer) -- outer encrypted layer
:param cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey
identity_key: service identity key
:param cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey
signing_key: service signing key
Parameters:
  • signing_cert (stem.descriptor.Ed25519CertificateV1) -- certificate signing this descriptor
  • revision_counter (int) -- descriptor revision number
  • blinding_nonce (bytes) -- 32 byte blinding factor to derive the blinding key
Returns:

str with the content of a descriptor

Raises :
  • ValueError if parameters are malformed
  • ImportError if cryptography is unavailable
classmethod create(attr=None, exclude=(), validate=True, sign=False, inner_layer=None, outer_layer=None, identity_key=None, signing_key=None, signing_cert=None, revision_counter=None, blinding_nonce=None)[source]
decrypt(onion_address)[source]

Decrypt this descriptor. Hidden serice descriptors contain two encryption layers (OuterLayer and InnerLayer).

Parameters:

onion_address (str) -- hidden service address this descriptor is from

Returns:

InnerLayer with our decrypted content

Raises :
  • ImportError if required cryptography or sha3 module is unavailable
  • ValueError if unable to decrypt or validation fails
static address_from_identity_key(key, suffix=True)[source]

Converts a hidden service identity key into its address. This accepts all key formats (private, public, or public bytes).

Parameters:
  • key (Ed25519PublicKey,Ed25519PrivateKey,bytes) -- hidden service identity key
  • suffix (bool) -- includes the '.onion' suffix if true, excluded otherwise
Returns:

unicode hidden service address

Raises :

ImportError if sha3 unsupported

static identity_key_from_address(onion_address)[source]

Converts a hidden service address into its public identity key.

Parameters:

onion_address (str) -- hidden service address

Returns:

bytes for the hidden service's public identity key

Raises :
  • ImportError if sha3 unsupported
  • ValueError if address malformed or checksum is invalid
class stem.descriptor.hidden_service.OuterLayer(content, validate=False)[source]

Bases: stem.descriptor.Descriptor

Initial encryped layer of a hidden service v3 descriptor (spec).

New in version 1.8.0.

Variables:
  • auth_type (str) -- * encryption scheme used for descriptor authorization
  • ephemeral_key (str) -- * base64 encoded x25519 public key
  • clients (dict) -- * mapping of authorized client ids to their AuthorizedClient
  • encrypted (str) -- * encrypted descriptor inner layer

* attribute is either required when we're parsed with validation or has a default value, others are left as None if undefined

classmethod create(attr=None, exclude=(), validate=True, sign=False, inner_layer=None, revision_counter=None, authorized_clients=None, subcredential=None, blinded_key=None)[source]
classmethod content(attr=None, exclude=(), validate=True, sign=False, inner_layer=None, revision_counter=None, authorized_clients=None, subcredential=None, blinded_key=None)[source]
class stem.descriptor.hidden_service.InnerLayer(content, validate=False, outer_layer=None)[source]

Bases: stem.descriptor.Descriptor

Second encryped layer of a hidden service v3 descriptor (spec).

New in version 1.8.0.

Variables:

* attribute is either required when we're parsed with validation or has a default value, others are left as None if undefined

classmethod create(attr=None, exclude=(), validate=True, sign=False, introduction_points=None)[source]
classmethod content(attr=None, exclude=(), sign=False, introduction_points=None)[source]
stem.descriptor.hidden_service.HiddenServiceDescriptor

alias of HiddenServiceDescriptorV2